Add unit tests for various modules: attachments grouping, department weather caching behaviors, economic module order sanitization, enriched order batching, and user cashier name lookups. Update related route logic for enhanced data fetching and caching integrations.
This commit is contained in:
@@ -67,56 +67,21 @@ class ordersRoute
|
||||
$orders = new orders_o();
|
||||
$orders->setView('orders_with_invoice_collections');
|
||||
$effectiveCustomer = self::resolveEffectiveCustomerNumber();
|
||||
$forcedFilters = $orders->forceRestrictFilters([
|
||||
...($has_permission_other ? [
|
||||
'department_id' => $department_ids
|
||||
] : []),
|
||||
...(!$has_permission_other && $effectiveCustomer !== null ? [
|
||||
'customer_id' => $effectiveCustomer
|
||||
] : []),
|
||||
]);
|
||||
$rawOrders = $orders->listObjectsWithPaginationIfSet(
|
||||
null,
|
||||
$forcedFilters
|
||||
);
|
||||
|
||||
$response->success(
|
||||
$orders->listObjectsWithPaginationIfSet(
|
||||
function ($order) {
|
||||
$order_obj = new orders_o();
|
||||
// Get the order object
|
||||
$order_obj->select((int)$order['id']);
|
||||
// Add the invoice status to the order
|
||||
$order['economic_invoice_module'] = (new economic_module_orders())->getByOrderId($order['id'])->asArray();
|
||||
// Add the total amount to the order
|
||||
$order['total_net_amount'] = $order_obj->getNetAmount();
|
||||
// Add the stripe status to the order
|
||||
$stripe_module_orders = (new stripe_module_orders_o())->select($order['id']);
|
||||
if ($stripe_module_orders->exists()) {
|
||||
$order['stripe_invoice_module'] = $stripe_module_orders->asArray();
|
||||
}
|
||||
// If the invoice collection is set, add it to the order
|
||||
if (!empty($order['invoice_collection_id'])) {
|
||||
$collected_order_invoices_obj = new collected_order_invoices_o();
|
||||
$collected_order_invoices_obj->select((int)$order['invoice_collection_id']);
|
||||
$order['invoice_collection'] = [
|
||||
'id' => $order['invoice_collection_id'],
|
||||
'closed_at' => $collected_order_invoices_obj->closed_at->value(),
|
||||
'booked_invoice_id' => $collected_order_invoices_obj->booked_invoice_id->value() ?? null,
|
||||
'processor' => (int)$collected_order_invoices_obj->processor->value() ?? null,
|
||||
];
|
||||
}
|
||||
// Get the customer
|
||||
$tmp_customer = (new users_o())->getUserByCustomerNumber((int)$order['customer_id']);
|
||||
// Add the customer name to the order
|
||||
$order['customer_name'] = (new users_o())->getCustomerName((int)$tmp_customer->customer_number->value());
|
||||
$order['user_id'] = (int)$tmp_customer->id;
|
||||
// Add the cashier name to the order
|
||||
$order['cashier_name'] = (new users_o())->getCashierName((int)$order['cashier_id']);
|
||||
$order['pending_handheld'] = $order_obj->isPendingHandheld();
|
||||
$order['attachments'] = $order_obj->listAttachments();
|
||||
$order['po'] = $order['po'] ?? null;
|
||||
$order['lane'] = $order['lane'] ?? null;
|
||||
/** @var array $order */
|
||||
return $order;
|
||||
},
|
||||
$orders->forceRestrictFilters([
|
||||
...($has_permission_other ? [
|
||||
'department_id' => $department_ids
|
||||
] : []),
|
||||
...(!$has_permission_other && $effectiveCustomer !== null ? [
|
||||
'customer_id' => $effectiveCustomer
|
||||
] : []),
|
||||
])
|
||||
)
|
||||
$this->enrichOrderListRows($rawOrders)
|
||||
);
|
||||
},
|
||||
[
|
||||
@@ -1007,6 +972,243 @@ class ordersRoute
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $orders
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
private function enrichOrderListRows(array $orders): array
|
||||
{
|
||||
if (empty($orders)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$orderIds = array_values(array_unique(array_filter(array_map('intval', array_column($orders, 'id')), static fn(int $id): bool => $id > 0)));
|
||||
$customerNumbers = array_values(array_unique(array_filter(array_map('intval', array_column($orders, 'customer_id')), static fn(int $id): bool => $id > 0)));
|
||||
$cashierIds = array_values(array_unique(array_filter(array_map('intval', array_column($orders, 'cashier_id')), static fn(int $id): bool => $id > 0)));
|
||||
|
||||
$netAmountsByOrderId = (new orders_o())->getNetAmountForOrders($orderIds);
|
||||
$economicModules = new economic_module_orders();
|
||||
$economicModules->ensureRowsForOrderIds($orderIds);
|
||||
$economicByOrderId = $economicModules->getByOrderIdsAsArray($orderIds);
|
||||
$stripeByOrderId = $this->getStripeModulesByOrderIds($orderIds);
|
||||
|
||||
$users = new users_o();
|
||||
$customerNamesByCustomerNumber = $users->getCustomerNames($customerNumbers);
|
||||
$userIdsByCustomerNumber = $this->getUserIdsByCustomerNumbers($customerNumbers);
|
||||
$cashierNamesById = $users->getCashierNames($cashierIds);
|
||||
$pendingHandheldByOrderId = $this->getPendingHandheldFlags($orderIds);
|
||||
$attachmentsByOrderId = (new attachments())->listMany('orders', $orderIds);
|
||||
|
||||
foreach ($orders as &$order) {
|
||||
$orderId = (int)($order['id'] ?? 0);
|
||||
$customerNumber = (int)($order['customer_id'] ?? 0);
|
||||
$cashierId = (int)($order['cashier_id'] ?? 0);
|
||||
|
||||
$order['economic_invoice_module'] = $economicByOrderId[$orderId] ?? [
|
||||
'id' => $orderId,
|
||||
'invoice_draft_id' => null,
|
||||
'invoice_id' => null,
|
||||
];
|
||||
$order['total_net_amount'] = (float)($netAmountsByOrderId[$orderId] ?? 0);
|
||||
|
||||
if (isset($stripeByOrderId[$orderId])) {
|
||||
$order['stripe_invoice_module'] = $stripeByOrderId[$orderId];
|
||||
}
|
||||
|
||||
if (!empty($order['invoice_collection_id'])) {
|
||||
$order['invoice_collection'] = [
|
||||
'id' => $order['invoice_collection_id'],
|
||||
'closed_at' => $order['closed_at'] ?? null,
|
||||
'booked_invoice_id' => $order['booked_invoice_id'] ?? null,
|
||||
'processor' => (int)($order['processor'] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
$customerName = $customerNamesByCustomerNumber[(string)$customerNumber] ?? null;
|
||||
if ($customerName === null && $customerNumber > 0) {
|
||||
$customerName = $users->getCustomerName($customerNumber);
|
||||
}
|
||||
$order['customer_name'] = $customerName;
|
||||
$order['user_id'] = (int)($userIdsByCustomerNumber[$customerNumber] ?? 0);
|
||||
$order['cashier_name'] = $cashierNamesById[$cashierId] ?? 'Unknown Cashier';
|
||||
$order['pending_handheld'] = (bool)($pendingHandheldByOrderId[$orderId] ?? false);
|
||||
$order['attachments'] = $attachmentsByOrderId[$orderId] ?? [];
|
||||
$order['po'] = $order['po'] ?? null;
|
||||
$order['lane'] = $order['lane'] ?? null;
|
||||
}
|
||||
unset($order);
|
||||
|
||||
return $orders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $orderIds
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
private function getStripeModulesByOrderIds(array $orderIds): array
|
||||
{
|
||||
$orderIds = array_values(array_unique(array_filter(array_map('intval', $orderIds), static fn(int $id): bool => $id > 0)));
|
||||
if (empty($orderIds)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rows = (new stripe_module_orders_o())->getFieldsWhereIn(
|
||||
['id' => $orderIds],
|
||||
['id', 'invoice_id', 'customer_id', 'url', 'created_at']
|
||||
);
|
||||
$byOrderId = [];
|
||||
foreach ($rows as $row) {
|
||||
$orderId = (int)($row['id'] ?? 0);
|
||||
if ($orderId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$invoiceId = trim((string)($row['invoice_id'] ?? ''));
|
||||
if ($invoiceId === '') {
|
||||
continue;
|
||||
}
|
||||
$stripeSnapshot = $this->getStripeInvoiceSnapshot($invoiceId);
|
||||
$byOrderId[$orderId] = [
|
||||
'id' => $orderId,
|
||||
'invoice_id' => $invoiceId,
|
||||
'customer_id' => (string)($row['customer_id'] ?? ''),
|
||||
'url' => (string)($row['url'] ?? ''),
|
||||
'created_at' => (string)($row['created_at'] ?? ''),
|
||||
'paid' => (bool)($stripeSnapshot['paid'] ?? false),
|
||||
'status' => $stripeSnapshot['status'] ?? null,
|
||||
'amount_due' => $stripeSnapshot['amount_due'] ?? null,
|
||||
'amount_paid' => $stripeSnapshot['amount_paid'] ?? null,
|
||||
];
|
||||
}
|
||||
|
||||
return $byOrderId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{paid: bool, status: mixed, amount_due: mixed, amount_paid: mixed}
|
||||
*/
|
||||
private function getStripeInvoiceSnapshot(string $invoiceId): array
|
||||
{
|
||||
$cached = $this->getCachedStripeInvoiceSnapshot($invoiceId);
|
||||
if ($cached !== null) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$invoice = (new stripe())->invoice->retrieve($invoiceId);
|
||||
$snapshot = [
|
||||
'paid' => (bool)($invoice->paid ?? false),
|
||||
'status' => $invoice->status ?? null,
|
||||
'amount_due' => $invoice->amount_due ?? null,
|
||||
'amount_paid' => $invoice->amount_paid ?? null,
|
||||
];
|
||||
$this->cacheStripeInvoiceSnapshot($invoiceId, $snapshot);
|
||||
|
||||
return $snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{paid: bool, status: mixed, amount_due: mixed, amount_paid: mixed}|null
|
||||
*/
|
||||
private function getCachedStripeInvoiceSnapshot(string $invoiceId): ?array
|
||||
{
|
||||
if (!defined('redis')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheKey = 'orders_stripe_invoice_snapshot_' . $invoiceId;
|
||||
$cachedRaw = redis->get($cacheKey);
|
||||
if (!is_string($cachedRaw) || $cachedRaw === '') {
|
||||
return null;
|
||||
}
|
||||
$decoded = json_decode($cachedRaw, true);
|
||||
return is_array($decoded) ? $decoded : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{paid: bool, status: mixed, amount_due: mixed, amount_paid: mixed} $snapshot
|
||||
*/
|
||||
private function cacheStripeInvoiceSnapshot(string $invoiceId, array $snapshot): void
|
||||
{
|
||||
if (!defined('redis')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$encoded = json_encode($snapshot);
|
||||
if (!is_string($encoded) || $encoded === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$cacheKey = 'orders_stripe_invoice_snapshot_' . $invoiceId;
|
||||
redis->set($cacheKey, $encoded);
|
||||
redis->expire($cacheKey, 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $customerNumbers
|
||||
* @return array<int, int> map: customer_number => user_id
|
||||
*/
|
||||
private function getUserIdsByCustomerNumbers(array $customerNumbers): array
|
||||
{
|
||||
$customerNumbers = array_values(array_unique(array_filter(array_map('intval', $customerNumbers), static fn(int $id): bool => $id > 0)));
|
||||
if (empty($customerNumbers)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$rows = (new users_o())->getFieldsWhereIn(
|
||||
['customer_number' => $customerNumbers],
|
||||
['id', 'customer_number']
|
||||
);
|
||||
|
||||
usort($rows, static fn(array $a, array $b): int => ((int)($a['id'] ?? 0)) <=> ((int)($b['id'] ?? 0)));
|
||||
$map = [];
|
||||
foreach ($rows as $row) {
|
||||
$customerNumber = (int)($row['customer_number'] ?? 0);
|
||||
if ($customerNumber <= 0 || isset($map[$customerNumber])) {
|
||||
continue;
|
||||
}
|
||||
$map[$customerNumber] = (int)($row['id'] ?? 0);
|
||||
}
|
||||
|
||||
// Keep parity with existing behavior that imports missing customer users via getUserByCustomerNumber.
|
||||
foreach ($customerNumbers as $customerNumber) {
|
||||
if (isset($map[$customerNumber])) {
|
||||
continue;
|
||||
}
|
||||
$user = (new users_o())->getUserByCustomerNumber($customerNumber);
|
||||
if ($user->exists()) {
|
||||
$map[$customerNumber] = (int)$user->id;
|
||||
}
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $orderIds
|
||||
* @return array<int, bool> map: order_id => pending_handheld
|
||||
*/
|
||||
private function getPendingHandheldFlags(array $orderIds): array
|
||||
{
|
||||
$orderIds = array_values(array_unique(array_filter(array_map('intval', $orderIds), static fn(int $id): bool => $id > 0)));
|
||||
if (empty($orderIds)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$flags = [];
|
||||
foreach ($orderIds as $orderId) {
|
||||
$flags[$orderId] = false;
|
||||
}
|
||||
if (!defined('redis')) {
|
||||
return $flags;
|
||||
}
|
||||
|
||||
$cached = (new orders_o())->getCachedForMultipleObjects('pending_handheld_cache_indicator', $orderIds);
|
||||
foreach ($orderIds as $index => $orderId) {
|
||||
$flags[$orderId] = ((int)($cached[$index] ?? 0) === 1);
|
||||
}
|
||||
|
||||
return $flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
* @param response $response
|
||||
|
||||
Reference in New Issue
Block a user