Files
itflow/api/v1/invoice_items/read.php
johnnyq cd565b73c7 Taxes stage 2: Tax Collected report rebuilt for filing with an Invoiced basis (each sent invoice in the month of its date) or Paid basis (each payment carrying its share of its invoice), tax by part of each rate with registration numbers so a state's and a county's parts count apart and parts named alike add up in one row, sales before tax and net of discounts split into taxable, exempt and non-taxable, tax paid on purchases by part and net tax collected less paid, exempt sales by client with certificate and expiry, quarterly or monthly with a chart and CSV export of the tax table or the exempt sales, archived payments left out; expenses and recurring expenses record the tax included in them with a rate worked out from the amount as typed or typed over from the receipt, a tax amount with no rate allowed, refunds giving their tax back, recurring expenses copying it to each expense recorded, vendor defaults filling it in, and the list and quick looks showing it; exports gain invoice subtotal, discount, tax and tax by part, quote and recurring invoice tax, expense before tax, tax and tax rate, and client tax rate and exemption columns; API adds a taxes read endpoint with each rate's parts, subtotal, tax, tax by part and registration numbers on invoice and quote reads, and each line's rate on invoice item reads; Admin > Taxes explains naming parts alike and links the report; demo data names Allegheny County's state part PA Sales Tax and taxes the company's own-use purchases; removes the unused getMonthlyTax and getQuarterlyTax; database 3.1.2 adds expense and recurring expense tax rate and amount; changelog updated
2026-10-17 13:27:53 -04:00

68 lines
2.6 KiB
PHP

<?php
/*
* API - Invoice Items - Read
* GET /api/v1/invoice_items/read.php
*
* Returns line items belonging to invoices scoped to the API key's client,
* each with its rate's tax_name and tax_percent.
*
* Parameters (GET):
* api_key required - Your API key
* invoice_id required* - Return items for a single invoice
* item_id required* - Return a single line item by its own ID
* * One of invoice_id or item_id must be provided
* client_id optional - Only return items on invoices for this client
* limit optional - Max rows to return (default 50)
* offset optional - Offset for pagination (default 0)
*
* Security:
* - invoice_items are always joined to invoices so that invoice_client_id
* is checked against the key user's client scope. A restricted key can never
* read items belonging to another client, even when item_id is supplied
* directly.
* - An optional client_id narrows the result further, within that scope. It is
* a filter, not a grant - it can never widen what the key can see.
*/
require_once '../validate_api_key.php';
require_once '../require_get_method.php';
if (isset($_GET['item_id'])) {
// Single line item by item_id — still JOIN to invoices to enforce client scope
$item_id = intval($_GET['item_id']);
$sql = mysqli_query($mysqli,
"SELECT ii.*, t.tax_name, t.tax_percent
FROM invoice_items ii
INNER JOIN invoices i ON i.invoice_id = ii.item_invoice_id
LEFT JOIN taxes t ON t.tax_id = ii.item_tax_id
WHERE ii.item_id = '$item_id'
AND 1=1 " . apiClientScopeSql('i.invoice_client_id') . "
LIMIT 1"
);
} elseif (isset($_GET['invoice_id'])) {
// All items on a specific invoice
$invoice_id = intval($_GET['invoice_id']);
$sql = mysqli_query($mysqli,
"SELECT ii.*, t.tax_name, t.tax_percent
FROM invoice_items ii
INNER JOIN invoices i ON i.invoice_id = ii.item_invoice_id
LEFT JOIN taxes t ON t.tax_id = ii.item_tax_id
WHERE ii.item_invoice_id = '$invoice_id'
AND 1=1 " . apiClientScopeSql('i.invoice_client_id') . "
ORDER BY ii.item_order ASC, ii.item_id ASC
LIMIT $limit OFFSET $offset"
);
} else {
// No filter supplied — reject the request
http_response_code(400);
echo json_encode([
'success' => 'False',
'message' => 'A filter is required. Please supply either invoice_id or item_id.',
'count' => 0,
'data' => []
]);
exit;
}
// Output
require_once "../read_output.php";