Customer Lifetime Value Summary
Summarizes order count, revenue, refunds, average order, and first/last purchase.
Function signature
ogBuildCustomerLifetimeValue(orders = array(), options = array())
Categories
- Ecommerce Workflows
Parameters
ordersOrder history rows used for customer lifetime-value calculation.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.
*/
/**
* Summarizes customer lifetime value from order records.
*
* Money is calculated in integer minor units. Unpaid/cancelled orders are skipped
* unless the caller supplies different paid statuses.
*
* @param array $orders Order records for one customer.
* @param array $options Paid-status and refund handling options.
* @return array Customer value summary.
*/
function ogBuildCustomerLifetimeValue($orders = array(), $options = array()) {
$result = array(
'success' => false,
'message' => '',
'data' => array()
);
if (!is_array($orders)) {
$result['message'] = 'Orders must be an array.';
return $result;
}
if (!is_array($options)) {
$options = array();
}
$paid_statuses = array('paid', 'captured', 'settled', 'completed');
if (!empty($options['paid_statuses']) && is_array($options['paid_statuses'])) {
$paid_statuses = $options['paid_statuses'];
}
$order_count = 0;
$gross_minor_units = 0;
$refund_minor_units = 0;
$first_purchase_at = 0;
$last_purchase_at = 0;
foreach ($orders as $order) {
if (!is_array($order)) {
continue;
}
$status = '';
if (!empty($order['payment_status'])) {
$status = strtolower(trim((string)$order['payment_status']));
}
if (!in_array($status, $paid_statuses, true)) {
continue;
}
$total = 0;
if (!empty($order['total_minor_units'])) {
$total = (int)$order['total_minor_units'];
}
$refund = 0;
if (!empty($order['refund_minor_units'])) {
$refund = (int)$order['refund_minor_units'];
}
$purchase_time = 0;
if (!empty($order['purchased_at'])) {
if (is_numeric($order['purchased_at'])) {
$purchase_time = (int)$order['purchased_at'];
} else {
$purchase_time = strtotime((string)$order['purchased_at']);
}
}
$order_count++;
$gross_minor_units += $total;
$refund_minor_units += $refund;
if ($purchase_time > 0) {
if ($first_purchase_at == 0 || $purchase_time < $first_purchase_at) {
$first_purchase_at = $purchase_time;
}
if ($purchase_time > $last_purchase_at) {
$last_purchase_at = $purchase_time;
}
}
}
$net_minor_units = $gross_minor_units - $refund_minor_units;
if ($net_minor_units < 0) {
$net_minor_units = 0;
}
$average_order_minor_units = 0;
if ($order_count > 0) {
$average_order_minor_units = (int)floor($net_minor_units / $order_count);
}
$result['success'] = true;
$result['message'] = 'Customer lifetime value summarized.';
$result['data'] = array(
'order_count' => $order_count,
'gross_minor_units' => $gross_minor_units,
'refund_minor_units' => $refund_minor_units,
'net_minor_units' => $net_minor_units,
'average_order_minor_units' => $average_order_minor_units,
'first_purchase_at' => $first_purchase_at,
'last_purchase_at' => $last_purchase_at
);
return $result;
}