From 4c8d38e97287a11ed086d31c48786ee0424833f9 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Mon, 24 Aug 2026 23:09:49 +0200 Subject: [PATCH] feat(admin): add analytics aggregator --- src/Services/Analytics.php | 89 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/Services/Analytics.php diff --git a/src/Services/Analytics.php b/src/Services/Analytics.php new file mode 100644 index 0000000..cd4ab7c --- /dev/null +++ b/src/Services/Analytics.php @@ -0,0 +1,89 @@ +db->select( + "SELECT substr(COALESCE(paidAt, createdAt), 1, 10) AS day, + COUNT(*) AS orderCount, + COALESCE(SUM(totalCents), 0) AS revenueCents + FROM orders + WHERE status IN ('paid', 'fulfilled') + GROUP BY day + ORDER BY day ASC" + ); + + $byDay = []; + foreach ($rows as $row) { + $byDay[$row['day']] = [ + 'orderCount' => (int) $row['orderCount'], + 'revenueCents' => (int) $row['revenueCents'], + ]; + } + + $series = []; + for ($offset = $days - 1; $offset >= 0; $offset--) { + $day = gmdate('Y-m-d', strtotime("-{$offset} days")); + $series[] = [ + 'day' => $day, + 'orderCount' => $byDay[$day]['orderCount'] ?? 0, + 'revenueCents' => $byDay[$day]['revenueCents'] ?? 0, + ]; + } + return $series; + } + + public function topProducts(int $limit = 5): array + { + return $this->db->select( + "SELECT oi.productId, + oi.productName AS name, + SUM(oi.quantity) AS unitsSold, + SUM(oi.quantity * oi.unitPriceCents) AS revenueCents + FROM orderItems oi + JOIN orders o ON o.id = oi.orderId + WHERE o.status IN ('paid', 'fulfilled') + GROUP BY oi.productName + ORDER BY unitsSold DESC, revenueCents DESC + LIMIT ?", + [$limit] + ); + } + + public function averageOrderValueCents(): int + { + return (int) round((float) $this->db->scalar( + "SELECT COALESCE(AVG(totalCents), 0) FROM orders WHERE status IN ('paid', 'fulfilled')" + )); + } + + public function unitsSold(): int + { + return (int) $this->db->scalar( + "SELECT COALESCE(SUM(oi.quantity), 0) + FROM orderItems oi + JOIN orders o ON o.id = oi.orderId + WHERE o.status IN ('paid', 'fulfilled')" + ); + } + + public function couponUsage(): array + { + return $this->db->select( + "SELECT couponCode, COUNT(*) AS orderCount, COALESCE(SUM(discountCents), 0) AS discountCents + FROM orders + WHERE couponCode IS NOT NULL AND couponCode != '' + GROUP BY couponCode + ORDER BY orderCount DESC" + ); + } +}