feat: phase 6 — dashboard widgets, sales & stock reports, user management, activity log

This commit is contained in:
sean
2026-08-25 19:25:40 +07:00
parent 28937a786e
commit feba1ec839
18 changed files with 1011 additions and 5 deletions
+66
View File
@@ -272,6 +272,72 @@ class OrderService extends InsForgeTableService
return $actor !== null && ($actor->isAdmin() || $actor->id === ($record['created_by'] ?? null));
}
/** @return array<string, int> status => jumlah order aktif */
public function countByStatus(): array
{
[$client] = $this->scoped();
$counts = [];
foreach (array_keys(self::TRANSITIONS) as $status) {
$counts[$status] = $client->countRecords($this->table(), [
'order_status' => $status,
'deleted_at' => 'null',
]);
}
return $counts;
}
public function recent(int $limit = 8): array
{
[$client] = $this->scoped();
return $client->listRecords($this->table(), [
'select' => 'id,order_number,order_date,order_status,customers(name)',
'deleted_at' => 'eq.null',
'order' => 'created_at.desc',
'limit' => $limit,
]);
}
/**
* Agregasi penjualan per produk dari order completed dalam periode (UTC).
*
* @return list<array{code: string, name: string, qty: int, revenue: int}>
*/
public function salesPerProduct(string $fromDate, string $toDate): array
{
[$client, $asUser] = $this->scoped();
$orders = $client->listRecords($this->table(), [
'select' => 'order_items(quantity,subtotal,products(code,name))',
'and' => sprintf(
'(order_status.eq.completed,completed_at.gte.%sT00:00:00+00:00,completed_at.lte.%sT23:59:59+00:00)',
$fromDate,
$toDate,
),
'limit' => 1000,
], asUser: $asUser);
$aggregated = [];
foreach ($orders as $order) {
foreach ($order['order_items'] ?? [] as $item) {
$code = data_get($item, 'products.code', '?');
$key = $code;
$aggregated[$key] ??= ['code' => $code, 'name' => data_get($item, 'products.name', ''), 'qty' => 0, 'revenue' => 0];
$aggregated[$key]['qty'] += (int) ($item['quantity'] ?? 0);
$aggregated[$key]['revenue'] += (int) ($item['subtotal'] ?? 0);
}
}
usort($aggregated, fn (array $a, array $b): int => $b['revenue'] <=> $a['revenue']);
return array_values($aggregated);
}
public function deliveryNoteData(string $orderId): array
{
[$client, $asUser] = $this->scoped();