Inventory Reservation Planner
Plans stock reservations for checkout without immediately reducing inventory incorrectly.
Function signature
ogPlanInventoryReservation(cart_lines = array(), stock_records = array())
Categories
- Ecommerce Workflows
Parameters
cart_linesCart line rows needing inventory reservation review.stock_recordsAvailable/reserved stock records keyed by SKU or product identity.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.
*/
/**
* Plans stock reservations for checkout without directly reducing inventory.
*
* Stock is checked against requested quantities and already-reserved quantities.
* Execution must still happen inside a database transaction at order-write time.
*
* @param array $cart_lines Cart lines with product_id and quantity.
* @param array $stock_records Stock rows keyed by product ID or containing product_id fields.
* @return array Reservation plan with shortages and reserve-ready rows.
*/
function ogPlanInventoryReservation($cart_lines = array(), $stock_records = array()) {
$result = array(
'success' => false,
'message' => '',
'data' => array()
);
if (!is_array($cart_lines)) {
$result['message'] = 'Cart lines must be an array.';
return $result;
}
if (!is_array($stock_records)) {
$result['message'] = 'Stock records must be an array.';
return $result;
}
$stock_by_product = array();
foreach ($stock_records as $key => $stock) {
if (!is_array($stock)) {
continue;
}
$product_id = 0;
if (!empty($stock['product_id'])) {
$product_id = (int)$stock['product_id'];
} elseif (is_numeric($key)) {
$product_id = (int)$key;
}
if ($product_id <= 0) {
continue;
}
$available = 0;
if (!empty($stock['available_quantity'])) {
$available = (int)$stock['available_quantity'];
}
$reserved = 0;
if (!empty($stock['reserved_quantity'])) {
$reserved = (int)$stock['reserved_quantity'];
}
$stock_by_product[$product_id] = array(
'available_quantity' => $available,
'reserved_quantity' => $reserved,
'net_available' => $available - $reserved
);
}
$reservations = array();
$shortages = array();
foreach ($cart_lines as $line) {
if (!is_array($line)) {
continue;
}
$product_id = 0;
if (!empty($line['product_id'])) {
$product_id = (int)$line['product_id'];
}
$quantity = 1;
if (!empty($line['quantity'])) {
$quantity = (int)$line['quantity'];
}
if ($product_id <= 0 || $quantity < 1) {
$shortages[] = array(
'product_id' => $product_id,
'requested_quantity' => $quantity,
'available_quantity' => 0,
'reason' => 'Invalid product or quantity.'
);
continue;
}
$net_available = 0;
if (!empty($stock_by_product[$product_id])) {
$net_available = (int)$stock_by_product[$product_id]['net_available'];
}
if ($net_available >= $quantity) {
$reservations[] = array(
'product_id' => $product_id,
'quantity' => $quantity,
'reservation_key' => hash('sha256', $product_id . ':' . $quantity . ':' . count($reservations))
);
} else {
$shortages[] = array(
'product_id' => $product_id,
'requested_quantity' => $quantity,
'available_quantity' => $net_available,
'reason' => 'Insufficient inventory.'
);
}
}
$result['success'] = empty($shortages);
if (empty($shortages)) {
$result['message'] = 'Inventory reservation plan is ready.';
} else {
$result['message'] = 'Inventory shortages were found.';
}
$result['data'] = array(
'reservations' => $reservations,
'shortages' => $shortages,
'requires_transaction' => true
);
return $result;
}