diff --git a/src/app/Http/Controllers/DashboardController.php b/src/app/Http/Controllers/DashboardController.php
index 6673c4b..186e314 100644
--- a/src/app/Http/Controllers/DashboardController.php
+++ b/src/app/Http/Controllers/DashboardController.php
@@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class DashboardController extends Controller
@@ -12,28 +13,45 @@ public function index()
return view('dashboard');
}
- public function summary(): JsonResponse
+ private function dateRange(Request $request): array
{
+ $from = $request->query('from');
+ $to = $request->query('to');
+ return [
+ $from ?: null,
+ $to ? $to . ' 23:59:59' : null,
+ ];
+ }
+
+ public function summary(Request $request): JsonResponse
+ {
+ [$from, $to] = $this->dateRange($request);
+
$totalSuppliers = DB::table('PL_SUPPLIERACCOUNT')->count();
$totalProducts = DB::table('STK_STOCKITEM')->where('ISACTVE', 'Y')->count();
$totalCustomers = DB::table('SL_CUSTOMERACCOUNT')->count();
- $purchaseSpend = DB::table('PL_BILLTRAN')
- ->selectRaw('COALESCE(SUM(QTYTOINVOICE * COSTPRICE / COSTPRICEPER), 0) as total')
- ->value('total');
+ $purchaseQ = DB::table('PL_BILLTRAN as il')
+ ->join('PL_BILL as i', 'il.REFNO', '=', 'i.REFNO');
+ if ($from) $purchaseQ->where('i.DOCDTETME', '>=', $from);
+ if ($to) $purchaseQ->where('i.DOCDTETME', '<=', $to);
+ $purchaseSpend = $purchaseQ->selectRaw('COALESCE(SUM(il.QTYTOINVOICE * il.COSTPRICE / il.COSTPRICEPER), 0) as total')->value('total');
- $salesRevenue = DB::table('SL_SALESINVOICETRAN')
- ->selectRaw('COALESCE(SUM(QTYTOINVOICE * SELLINGPRICE / SELLINGPRICEPER), 0) as total')
- ->value('total');
+ $salesQ = DB::table('SL_SALESINVOICETRAN as sl')
+ ->join('SL_SALESINVOICE as si', 'sl.REFNO', '=', 'si.REFNO');
+ if ($from) $salesQ->where('si.DOCDTETME', '>=', $from);
+ if ($to) $salesQ->where('si.DOCDTETME', '<=', $to);
- $salesCost = DB::table('SL_SALESINVOICETRAN')
- ->selectRaw('COALESCE(SUM(QTYTOINVOICE * COSTPRICE / COSTPRICEPER), 0) as total')
- ->value('total');
+ $salesRevenue = (clone $salesQ)->selectRaw('COALESCE(SUM(sl.QTYTOINVOICE * sl.SELLINGPRICE / sl.SELLINGPRICEPER), 0) as total')->value('total');
+ $salesCost = (clone $salesQ)->selectRaw('COALESCE(SUM(sl.QTYTOINVOICE * sl.COSTPRICE / sl.COSTPRICEPER), 0) as total')->value('total');
$grossProfit = $salesRevenue - $salesCost;
$margin = $salesRevenue > 0 ? round(($grossProfit / $salesRevenue) * 100, 1) : 0;
- $totalInvoices = DB::table('PL_BILL')->count();
+ $invoiceQ = DB::table('PL_BILL');
+ if ($from) $invoiceQ->where('DOCDTETME', '>=', $from);
+ if ($to) $invoiceQ->where('DOCDTETME', '<=', $to);
+ $totalInvoices = $invoiceQ->count();
return response()->json([
'total_suppliers' => $totalSuppliers,
@@ -47,29 +65,37 @@ public function summary(): JsonResponse
]);
}
- public function topSuppliers(): JsonResponse
+ public function topSuppliers(Request $request): JsonResponse
{
- $suppliers = DB::table('PL_BILLTRAN as il')
+ [$from, $to] = $this->dateRange($request);
+
+ $q = DB::table('PL_BILLTRAN as il')
->join('PL_BILL as i', 'il.REFNO', '=', 'i.REFNO')
->selectRaw('i.ACCNO as code, i.SUPLNME as name, COUNT(DISTINCT i.REFNO) as invoice_count, SUM(il.QTYTOINVOICE * il.COSTPRICE / il.COSTPRICEPER) as total_spend, SUM(il.QTYTOINVOICE) as total_qty')
->groupBy('i.ACCNO', 'i.SUPLNME')
->orderByDesc('total_spend')
- ->limit(10)
- ->get();
+ ->limit(10);
+ if ($from) $q->where('i.DOCDTETME', '>=', $from);
+ if ($to) $q->where('i.DOCDTETME', '<=', $to);
- return response()->json($suppliers);
+ return response()->json($q->get());
}
- public function topProducts(): JsonResponse
+ public function topProducts(Request $request): JsonResponse
{
- $products = DB::table('SL_SALESINVOICETRAN as sl')
+ [$from, $to] = $this->dateRange($request);
+
+ $q = DB::table('SL_SALESINVOICETRAN as sl')
->join('STK_STOCKITEM as p', 'sl.STOCKCODE', '=', 'p.STOCKCODE')
+ ->join('SL_SALESINVOICE as si', 'sl.REFNO', '=', 'si.REFNO')
->selectRaw('sl.STOCKCODE as code, p.DESCRIPTION as name, SUM(sl.QTYTOINVOICE) as total_qty_sold, SUM(sl.QTYTOINVOICE * sl.SELLINGPRICE / sl.SELLINGPRICEPER) as total_revenue, SUM(sl.QTYTOINVOICE * sl.COSTPRICE / sl.COSTPRICEPER) as total_cost')
->groupBy('sl.STOCKCODE', 'p.DESCRIPTION')
->orderByDesc('total_revenue')
- ->limit(10)
- ->get()
- ->map(function ($item) {
+ ->limit(10);
+ if ($from) $q->where('si.DOCDTETME', '>=', $from);
+ if ($to) $q->where('si.DOCDTETME', '<=', $to);
+
+ $products = $q->get()->map(function ($item) {
$item->margin = $item->total_revenue > 0
? round((($item->total_revenue - $item->total_cost) / $item->total_revenue) * 100, 1)
: 0;
@@ -79,29 +105,36 @@ public function topProducts(): JsonResponse
return response()->json($products);
}
- public function spendOverTime(): JsonResponse
+ public function spendOverTime(Request $request): JsonResponse
{
- $data = DB::table('PL_BILLTRAN as il')
+ [$from, $to] = $this->dateRange($request);
+
+ $q = DB::table('PL_BILLTRAN as il')
->join('PL_BILL as i', 'il.REFNO', '=', 'i.REFNO')
->selectRaw("DATE_FORMAT(i.DOCDTETME, '%Y-%m') as month, SUM(il.QTYTOINVOICE * il.COSTPRICE / il.COSTPRICEPER) as total_spend")
->whereNotNull('i.DOCDTETME')
->groupByRaw("DATE_FORMAT(i.DOCDTETME, '%Y-%m')")
- ->orderBy('month')
- ->get();
+ ->orderBy('month');
+ if ($from) $q->where('i.DOCDTETME', '>=', $from);
+ if ($to) $q->where('i.DOCDTETME', '<=', $to);
- return response()->json($data);
+ return response()->json($q->get());
}
- public function salesOverTime(): JsonResponse
+ public function salesOverTime(Request $request): JsonResponse
{
- $data = DB::table('SL_SALESINVOICETRAN as sl')
+ [$from, $to] = $this->dateRange($request);
+
+ $q = DB::table('SL_SALESINVOICETRAN as sl')
->join('SL_SALESINVOICE as si', 'sl.REFNO', '=', 'si.REFNO')
->selectRaw("DATE_FORMAT(si.DOCDTETME, '%Y-%m') as month, SUM(sl.QTYTOINVOICE * sl.SELLINGPRICE / sl.SELLINGPRICEPER) as total_revenue, SUM(sl.QTYTOINVOICE * sl.COSTPRICE / sl.COSTPRICEPER) as total_cost")
->whereNotNull('si.DOCDTETME')
->groupByRaw("DATE_FORMAT(si.DOCDTETME, '%Y-%m')")
- ->orderBy('month')
- ->get()
- ->map(function ($item) {
+ ->orderBy('month');
+ if ($from) $q->where('si.DOCDTETME', '>=', $from);
+ if ($to) $q->where('si.DOCDTETME', '<=', $to);
+
+ $data = $q->get()->map(function ($item) {
$item->gross_profit = round($item->total_revenue - $item->total_cost, 2);
return $item;
});
@@ -109,17 +142,21 @@ public function salesOverTime(): JsonResponse
return response()->json($data);
}
- public function categoryBreakdown(): JsonResponse
+ public function categoryBreakdown(Request $request): JsonResponse
{
- $data = DB::table('SL_SALESINVOICETRAN as sl')
+ [$from, $to] = $this->dateRange($request);
+
+ $q = DB::table('SL_SALESINVOICETRAN as sl')
->join('STK_STOCKITEM as p', 'sl.STOCKCODE', '=', 'p.STOCKCODE')
+ ->join('SL_SALESINVOICE as si', 'sl.REFNO', '=', 'si.REFNO')
->leftJoin('STK_STOCKCATEGORY as c', 'p.CATEGORY', '=', 'c.STCKCTGRYCDE')
->selectRaw("COALESCE(c.STCKCTGRYDESC, 'Uncategorized') as category, SUM(sl.QTYTOINVOICE * sl.SELLINGPRICE / sl.SELLINGPRICEPER) as revenue, SUM(sl.QTYTOINVOICE * sl.COSTPRICE / sl.COSTPRICEPER) as cost, SUM(sl.QTYTOINVOICE) as qty")
->groupByRaw("COALESCE(c.STCKCTGRYDESC, 'Uncategorized')")
- ->orderByDesc('revenue')
- ->get();
+ ->orderByDesc('revenue');
+ if ($from) $q->where('si.DOCDTETME', '>=', $from);
+ if ($to) $q->where('si.DOCDTETME', '<=', $to);
- return response()->json($data);
+ return response()->json($q->get());
}
public function supplierProducts(string $supplierCode): JsonResponse
@@ -154,4 +191,61 @@ public function supplierProducts(string $supplierCode): JsonResponse
'timeline' => $timeline,
]);
}
+
+ public function productDetails(Request $request): JsonResponse
+ {
+ $stockCode = $request->query('code', '');
+ if (!$stockCode) {
+ return response()->json(['error' => 'Missing code parameter'], 400);
+ }
+
+ $product = DB::table('STK_STOCKITEM as p')
+ ->leftJoin('STK_STOCKCATEGORY as c', 'p.CATEGORY', '=', 'c.STCKCTGRYCDE')
+ ->where('p.STOCKCODE', $stockCode)
+ ->selectRaw("p.STOCKCODE as code, p.DESCRIPTION as name, COALESCE(c.STCKCTGRYDESC, 'Uncategorized') as category")
+ ->first();
+
+ // Sales timeline
+ $salesTimeline = DB::table('SL_SALESINVOICETRAN as sl')
+ ->join('SL_SALESINVOICE as si', 'sl.REFNO', '=', 'si.REFNO')
+ ->where('sl.STOCKCODE', $stockCode)
+ ->whereNotNull('si.DOCDTETME')
+ ->selectRaw("DATE_FORMAT(si.DOCDTETME, '%Y-%m') as month, SUM(sl.QTYTOINVOICE) as qty_sold, SUM(sl.QTYTOINVOICE * sl.SELLINGPRICE / sl.SELLINGPRICEPER) as revenue, SUM(sl.QTYTOINVOICE * sl.COSTPRICE / sl.COSTPRICEPER) as cost")
+ ->groupByRaw("DATE_FORMAT(si.DOCDTETME, '%Y-%m')")
+ ->orderBy('month')
+ ->get()
+ ->map(function ($item) {
+ $item->profit = round($item->revenue - $item->cost, 2);
+ return $item;
+ });
+
+ // Top customers buying this product
+ $topCustomers = DB::table('SL_SALESINVOICETRAN as sl')
+ ->join('SL_SALESINVOICE as si', 'sl.REFNO', '=', 'si.REFNO')
+ ->join('SL_CUSTOMERACCOUNT as ca', 'si.ACCNO', '=', 'ca.DBTRCDE')
+ ->where('sl.STOCKCODE', $stockCode)
+ ->selectRaw('ca.DBTRCDE as code, ca.DBTRNME as name, SUM(sl.QTYTOINVOICE) as total_qty, SUM(sl.QTYTOINVOICE * sl.SELLINGPRICE / sl.SELLINGPRICEPER) as total_revenue, COUNT(DISTINCT si.REFNO) as invoice_count')
+ ->groupBy('ca.DBTRCDE', 'ca.DBTRNME')
+ ->orderByDesc('total_revenue')
+ ->limit(15)
+ ->get();
+
+ // Suppliers providing this product
+ $suppliers = DB::table('PL_BILLTRAN as il')
+ ->join('PL_BILL as i', 'il.REFNO', '=', 'i.REFNO')
+ ->join('PL_SUPPLIERACCOUNT as sa', 'i.ACCNO', '=', 'sa.SUPLCDE')
+ ->where('il.STOCKCODE', $stockCode)
+ ->selectRaw('sa.SUPLCDE as code, sa.SUPLNME as name, SUM(il.QTYTOINVOICE) as total_qty, SUM(il.QTYTOINVOICE * il.COSTPRICE / il.COSTPRICEPER) as total_cost, COUNT(DISTINCT i.REFNO) as invoice_count')
+ ->groupBy('sa.SUPLCDE', 'sa.SUPLNME')
+ ->orderByDesc('total_cost')
+ ->limit(10)
+ ->get();
+
+ return response()->json([
+ 'product' => $product,
+ 'sales_timeline' => $salesTimeline,
+ 'top_customers' => $topCustomers,
+ 'suppliers' => $suppliers,
+ ]);
+ }
}
diff --git a/src/resources/views/dashboard.blade.php b/src/resources/views/dashboard.blade.php
index 03541b2..1bc364f 100644
--- a/src/resources/views/dashboard.blade.php
+++ b/src/resources/views/dashboard.blade.php
@@ -117,6 +117,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -273,12 +284,12 @@