diff --git a/app/Http/Controllers/AnalysisController.php b/app/Http/Controllers/AnalysisController.php
index 62e7ac9..3d868d5 100644
--- a/app/Http/Controllers/AnalysisController.php
+++ b/app/Http/Controllers/AnalysisController.php
@@ -8,6 +8,7 @@
use App\Models\Expense;
use App\Models\Order;
use App\Models\OrderItem;
+use App\Models\Payroll;
use App\Models\Purchase;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
@@ -20,6 +21,7 @@ public function __invoke()
'total_sales' => $this->getStats(fn () => Order::count()),
'total_revenue' => $this->getStats(fn () => Order::sum('total')),
'total_expenses' => $this->getStats(fn () => Expense::sum('amount')),
+ 'total_payrolls' => $this->getStats(fn () => Payroll::sum('total_salary')),
'cogs' => $this->getStats(fn () => Order::sum('hpp')),
'total_discount' => $this->getStats(fn () => Order::sum('discount')),
'total_purchases' => $this->getStats(fn () => Purchase::sum('total')),
@@ -29,7 +31,11 @@ public function __invoke()
$stats['aov'] = $this->calculateAov($stats['total_revenue'], $stats['total_sales']);
$stats['gross_profit'] = $this->calculateDiff($stats['total_revenue'], $stats['cogs']);
- $stats['net_profit'] = $this->calculateDiff($stats['gross_profit'], $stats['total_expenses']);
+ $stats['net_profit'] = [
+ 'value' => $stats['gross_profit']['value'] - $stats['total_expenses']['value'] - $stats['total_payrolls']['value'],
+ 'yesterday' => null,
+ 'change' => null,
+ ];
$stats['profit_margin'] = $this->calculateMargin($stats['net_profit'], $stats['total_revenue']);
// Revenue vs Purchases per month (this year)
@@ -131,9 +137,55 @@ public function __invoke()
];
});
+ // Revenue & Profit per month
+ $ordersByMonth = DB::table('orders')
+ ->select(
+ DB::raw('MONTH(created_at) as month'),
+ DB::raw('SUM(total) as revenue'),
+ DB::raw('SUM(hpp) as cogs')
+ )
+ ->groupBy(DB::raw('MONTH(created_at)'))
+ ->get();
+
+ $expensesByMonth = DB::table('expenses')
+ ->select(
+ DB::raw('MONTH(created_at) as month'),
+ DB::raw('SUM(amount) as total')
+ )
+ ->groupBy(DB::raw('MONTH(created_at)'))
+ ->get();
+
+ $payrollsByMonth = DB::table('payrolls')
+ ->select(
+ DB::raw('MONTH(period_month) as month'),
+ DB::raw('SUM(total_salary) as total')
+ )
+ ->whereNull('deleted_at')
+ ->groupBy(DB::raw('MONTH(period_month)'))
+ ->get();
+
+ $revenueVsProfit = collect(range(1, 12))->map(function ($month) use ($ordersByMonth, $expensesByMonth, $payrollsByMonth, $monthNames) {
+ $orderFound = $ordersByMonth->firstWhere('month', $month);
+ $expenseFound = $expensesByMonth->firstWhere('month', $month);
+ $payrollFound = $payrollsByMonth->firstWhere('month', $month);
+
+ $revenue = $orderFound ? (float) $orderFound->revenue : 0;
+ $cogs = $orderFound ? (float) $orderFound->cogs : 0;
+ $expense = $expenseFound ? (float) $expenseFound->total : 0;
+ $payroll = $payrollFound ? (float) $payrollFound->total : 0;
+ $profit = $revenue - $cogs - $expense - $payroll;
+
+ return [
+ 'month' => $monthNames[$month - 1],
+ 'revenue' => $revenue,
+ 'profit' => $profit,
+ ];
+ });
+
return Inertia::render('analysis', [
'stats' => $stats,
'salesByMonth' => $salesByMonth,
+ 'revenueVsProfit' => $revenueVsProfit,
'salesByHour' => $salesByHour,
'paymentMethods' => $paymentMethods,
'orderStatuses' => $orderStatuses,
diff --git a/resources/js/components/charts/revenue-vs-profit-chart.tsx b/resources/js/components/charts/revenue-vs-profit-chart.tsx
new file mode 100644
index 0000000..a08610a
--- /dev/null
+++ b/resources/js/components/charts/revenue-vs-profit-chart.tsx
@@ -0,0 +1,88 @@
+"use client"
+
+import { CartesianGrid, Line, LineChart, XAxis } from "recharts"
+
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle
+} from "@/components/ui/card"
+import {
+ ChartContainer,
+ ChartTooltip,
+ ChartTooltipContent,
+ type ChartConfig,
+} from "@/components/ui/chart"
+import { formatCurrency } from "@/lib/formatters"
+
+export const description = "Perbandingan Pendapatan vs Laba Bersih per bulan."
+
+const chartConfig = {
+ revenue: {
+ label: "Pendapatan",
+ color: "var(--chart-1)",
+ },
+ profit: {
+ label: "Laba Bersih",
+ color: "var(--chart-2)",
+ },
+} satisfies ChartConfig
+
+export function RevenueVsProfitChart({ data }: { data: any[] }) {
+ return (
+
+
+ Pendapatan vs Laba Bersih
+ Perbandingan Pendapatan vs Laba Bersih per bulan.
+
+
+
+
+
+ value.slice(0, 3)}
+ />
+ [
+ formatCurrency(Number(value)),
+ ` - ${chartConfig[name as keyof typeof chartConfig]?.label ?? name}`,
+ ]}
+ />
+ }
+ />
+
+
+
+
+
+
+ )
+}
diff --git a/resources/js/pages/analysis.tsx b/resources/js/pages/analysis.tsx
index ac6d99b..238ca8d 100644
--- a/resources/js/pages/analysis.tsx
+++ b/resources/js/pages/analysis.tsx
@@ -4,11 +4,12 @@ import type { AnalysisPageProps } from '@/types';
import { Head, usePage } from '@inertiajs/react';
import { CustomBarChart } from '../components/charts/bar-chart';
import { CustomPieChart } from '../components/charts/pie-chart';
-import { SalesByHourChart } from '../components/charts/sales-by-hour-chart';
+import { RevenueVsProfitChart } from '../components/charts/revenue-vs-profit-chart';
import { RevenueVsPurchasesChart } from '../components/charts/revenue-vs-purchases-chart';
+import { SalesByHourChart } from '../components/charts/sales-by-hour-chart';
export default function Analisa() {
- const { stats, salesByMonth, salesByHour, paymentMethods, orderStatuses, orderChannels, topProducts, topCustomers } =
+ const { stats, salesByMonth, revenueVsProfit, salesByHour, paymentMethods, orderStatuses, orderChannels, topProducts, topCustomers } =
usePage().props;
return (
@@ -33,6 +34,7 @@ export default function Analisa() {
{ title: "Total Diskon", stat: stats.total_discount },
{ title: "Laba Kotor", stat: stats.gross_profit },
{ title: "Laba Bersih", stat: stats.net_profit },
+ { title: "Total Gaji", stat: stats.total_payrolls },
{ title: "Total Pembelian", stat: stats.total_purchases },
{ title: "Produk Terjual", stat: stats.products_sold, isCurrency: false },
{ title: "Total Pelanggan", stat: stats.total_customers, isCurrency: false },
@@ -51,6 +53,9 @@ export default function Analisa() {
+
+
+