Skip to content
← Back to Functions
Code

Cart Totals Calculator

Calculates subtotal, discounts, tax estimates, shipping estimates, and grand total.

Function signature

ogCalculateCartTotals(input = array(), options = array())

Categories

  • Ecommerce Workflows

Parameters

inputStructured workflow input array documented by this helper.optionsOptional documented policy controls for the helper.

Return value

Public-safe status string returned by the function for 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 file paths, routes, email tokens, cart totals, discount rules, and tax-region rules 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.
 */

/**
 * Calculates subtotal, discounts, tax estimates, shipping estimates, and grand total.
 *
 * Primary use case: Cart and checkout pages.
 * Typical inputs: cart lines, pricing rules.
 * Typical output: cart totals.
 *
 * Implementation note: Use integer minor units, not floats.
 *
 * @param array $input Structured input values for this helper contract.
 * @param array $options Optional policy and formatting controls.
 * @return array Structured result data with success, message, and data keys.
 */
function ogCalculateCartTotals($input = array(), $options = array()) {
	$result = array(
		'success' => false,
		'message' => '',
		'data' => array()
	);

	if (!is_array($input)) {
		$result['message'] = 'Input must be an array.';
		return $result;
	}

	if (!is_array($options)) {
		$options = array();
	}

	$lines = array();
	if (!empty($input['lines']) && is_array($input['lines'])) {
		$lines = $input['lines'];
	}
	$discounts = array();
	if (!empty($input['discounts']) && is_array($input['discounts'])) {
		$discounts = $input['discounts'];
	}

	$subtotal = 0;
	foreach ($lines as $line) {
		if (!is_array($line)) {
			continue;
		}
		$price = 0;
		$quantity = 1;
		if (!empty($line['price_minor_units'])) {
			$price = (int)$line['price_minor_units'];
		}
		if (!empty($line['quantity'])) {
			$quantity = (int)$line['quantity'];
		}
		if ($price < 0) {
			$price = 0;
		}
		if ($quantity < 1) {
			$quantity = 1;
		}
		$subtotal += ($price * $quantity);
	}

	$discount_total = 0;
	foreach ($discounts as $discount) {
		$amount = 0;
		if (is_array($discount) && !empty($discount['amount_minor_units'])) {
			$amount = (int)$discount['amount_minor_units'];
		}
		if ($amount > 0) {
			$discount_total += $amount;
		}
	}
	if ($discount_total > $subtotal) {
		$discount_total = $subtotal;
	}

	$tax = 0;
	if (!empty($input['tax_minor_units'])) {
		$tax = (int)$input['tax_minor_units'];
	}
	$shipping = 0;
	if (!empty($input['shipping_minor_units'])) {
		$shipping = (int)$input['shipping_minor_units'];
	}
	if ($tax < 0) {
		$tax = 0;
	}
	if ($shipping < 0) {
		$shipping = 0;
	}

	$grand_total = $subtotal - $discount_total + $tax + $shipping;

	$result['success'] = true;
	$result['message'] = 'Cart totals calculated.';
	$result['data'] = array(
		'subtotal_minor_units' => $subtotal,
		'discount_minor_units' => $discount_total,
		'tax_minor_units' => $tax,
		'shipping_minor_units' => $shipping,
		'grand_total_minor_units' => $grand_total
	);

	return $result;
}