Invoice Line Builder
Builds invoice-ready line items from cart/order records.
Function signature
ogBuildInvoiceLines(order_lines = array(), options = array())
Categories
- Ecommerce Workflows
Parameters
order_linesValidated order line rows used to build invoice totals.optionsOptional documented policy controls for this helper.Return value
Public-safe status string returned by the function for explicit controller branching or logging.
- success
- message
- data
Compatibility
Existing function name, slug, path, and call order preserved; advertised metadata corrected to the actual source behavior.
Minimum PHP version: 7.4
Security notes
Use caller-owned allowlists and context-specific escaping; validate admin actions, export fields, privacy plans, cache keys, templates, settings, routes, and ecommerce policies before production use.
Code
<?php
/*
* Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
* Free for personal and internal use. Paid project use requires visible credit
* to Jeffery L. Paris. Corporate use requires a paid license fee unless a
* separate written license states otherwise.
*/
/**
* Builds invoice-ready line snapshots from order/cart lines.
*
* Money values are handled as integer minor units. The function returns a plan
* and does not write invoice records by itself.
*
* @param array $order_lines Order lines with title, quantity, unit price, discounts, and tax values.
* @param array $options Optional invoice formatting and currency options.
* @return array Invoice lines with totals and warnings.
*/
function ogBuildInvoiceLines($order_lines = array(), $options = array()) {
$result = array(
'success' => false,
'message' => '',
'data' => array()
);
if (!is_array($order_lines)) {
$result['message'] = 'Order lines must be an array.';
return $result;
}
if (!is_array($options)) {
$options = array();
}
$currency = 'USD';
if (!empty($options['currency'])) {
$currency = strtoupper(trim((string)$options['currency']));
}
$invoice_lines = array();
$subtotal_minor_units = 0;
$discount_minor_units = 0;
$tax_minor_units = 0;
$warnings = array();
foreach ($order_lines as $index => $line) {
if (!is_array($line)) {
$warnings[] = 'Skipped non-array line at index ' . (string)$index . '.';
continue;
}
$title = 'Line Item';
if (!empty($line['title'])) {
$title = trim((string)$line['title']);
}
$quantity = 1;
if (!empty($line['quantity'])) {
$quantity = (int)$line['quantity'];
}
if ($quantity < 1) {
$quantity = 1;
}
$unit_price_minor_units = 0;
if (!empty($line['unit_price_minor_units'])) {
$unit_price_minor_units = (int)$line['unit_price_minor_units'];
}
$line_discount_minor_units = 0;
if (!empty($line['discount_minor_units'])) {
$line_discount_minor_units = (int)$line['discount_minor_units'];
}
$line_tax_minor_units = 0;
if (!empty($line['tax_minor_units'])) {
$line_tax_minor_units = (int)$line['tax_minor_units'];
}
$line_subtotal = $unit_price_minor_units * $quantity;
$line_total = $line_subtotal - $line_discount_minor_units + $line_tax_minor_units;
if ($line_total < 0) {
$line_total = 0;
}
$subtotal_minor_units += $line_subtotal;
$discount_minor_units += $line_discount_minor_units;
$tax_minor_units += $line_tax_minor_units;
$invoice_lines[] = array(
'title' => $title,
'quantity' => $quantity,
'unit_price_minor_units' => $unit_price_minor_units,
'subtotal_minor_units' => $line_subtotal,
'discount_minor_units' => $line_discount_minor_units,
'tax_minor_units' => $line_tax_minor_units,
'total_minor_units' => $line_total,
'currency' => $currency
);
}
$grand_total = $subtotal_minor_units - $discount_minor_units + $tax_minor_units;
if ($grand_total < 0) {
$grand_total = 0;
}
$result['success'] = true;
$result['message'] = 'Invoice lines built.';
$result['data'] = array(
'lines' => $invoice_lines,
'subtotal_minor_units' => $subtotal_minor_units,
'discount_minor_units' => $discount_minor_units,
'tax_minor_units' => $tax_minor_units,
'grand_total_minor_units' => $grand_total,
'currency' => $currency,
'warnings' => $warnings
);
return $result;
}