feat: add analysis feature tests and support for cross-database date extraction in AnalysisController
This commit is contained in:
parent
b62dbf32d9
commit
120c5d28e8
@ -56,21 +56,24 @@ public function __invoke(Request $request)
|
||||
];
|
||||
$stats['profit_margin'] = $this->calculateMargin($stats['net_profit'], $stats['total_revenue']);
|
||||
|
||||
$isSqlite = DB::getDriverName() === 'sqlite';
|
||||
$monthSelect = $isSqlite ? "CAST(strftime('%m', created_at) AS INTEGER)" : 'MONTH(created_at)';
|
||||
|
||||
// Revenue vs Purchases per month
|
||||
$revenueByMonth = $applyFilter(DB::table('orders'))
|
||||
->select(
|
||||
DB::raw('MONTH(created_at) as month'),
|
||||
DB::raw("$monthSelect as month"),
|
||||
DB::raw('SUM(total) as total')
|
||||
)
|
||||
->groupBy(DB::raw('MONTH(created_at)'))
|
||||
->groupBy(DB::raw($monthSelect))
|
||||
->get();
|
||||
|
||||
$purchasesByMonth = $applyFilter(DB::table('purchases'))
|
||||
->select(
|
||||
DB::raw('MONTH(created_at) as month'),
|
||||
DB::raw("$monthSelect as month"),
|
||||
DB::raw('SUM(total) as total')
|
||||
)
|
||||
->groupBy(DB::raw('MONTH(created_at)'))
|
||||
->groupBy(DB::raw($monthSelect))
|
||||
->get();
|
||||
|
||||
$monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'];
|
||||
@ -138,12 +141,14 @@ public function __invoke(Request $request)
|
||||
->limit(5)
|
||||
->get();
|
||||
|
||||
$hourSelect = $isSqlite ? "CAST(strftime('%H', created_at) AS INTEGER)" : 'HOUR(created_at)';
|
||||
|
||||
$salesByHourRaw = $applyFilter(DB::table('orders'))
|
||||
->select(
|
||||
DB::raw('HOUR(created_at) as hour'),
|
||||
DB::raw("$hourSelect as hour"),
|
||||
DB::raw('COUNT(*) as total')
|
||||
)
|
||||
->groupBy(DB::raw('HOUR(created_at)'))
|
||||
->groupBy(DB::raw($hourSelect))
|
||||
->get();
|
||||
|
||||
$salesByHour = collect(range(0, 23))->map(function ($hour) use ($salesByHourRaw) {
|
||||
@ -158,29 +163,30 @@ public function __invoke(Request $request)
|
||||
// Revenue & Profit & Volume per month
|
||||
$ordersByMonth = $applyFilter(DB::table('orders'))
|
||||
->select(
|
||||
DB::raw('MONTH(created_at) as month'),
|
||||
DB::raw("$monthSelect as month"),
|
||||
DB::raw('SUM(total) as revenue'),
|
||||
DB::raw('SUM(cogs) as cogs'),
|
||||
DB::raw('COUNT(*) as count')
|
||||
)
|
||||
->groupBy(DB::raw('MONTH(created_at)'))
|
||||
->groupBy(DB::raw($monthSelect))
|
||||
->get();
|
||||
|
||||
$expensesByMonth = $applyFilter(DB::table('expenses'))
|
||||
->select(
|
||||
DB::raw('MONTH(created_at) as month'),
|
||||
DB::raw("$monthSelect as month"),
|
||||
DB::raw('SUM(amount) as total')
|
||||
)
|
||||
->groupBy(DB::raw('MONTH(created_at)'))
|
||||
->groupBy(DB::raw($monthSelect))
|
||||
->get();
|
||||
|
||||
$monthSelectPeriod = $isSqlite ? "CAST(strftime('%m', period_month) AS INTEGER)" : 'MONTH(period_month)';
|
||||
$payrollsByMonth = $applyFilter(DB::table('payrolls'), 'period_month')
|
||||
->select(
|
||||
DB::raw('MONTH(period_month) as month'),
|
||||
DB::raw("$monthSelectPeriod as month"),
|
||||
DB::raw('SUM(total_salary) as total')
|
||||
)
|
||||
->whereNull('deleted_at')
|
||||
->groupBy(DB::raw('MONTH(period_month)'))
|
||||
->groupBy(DB::raw($monthSelectPeriod))
|
||||
->get();
|
||||
|
||||
$revenueVsProfit = collect(range(1, 12))->map(function ($month) use ($ordersByMonth, $expensesByMonth, $payrollsByMonth, $monthNames) {
|
||||
|
||||
98
tests/Feature/Admin/AnalysisTest.php
Normal file
98
tests/Feature/Admin/AnalysisTest.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Expense;
|
||||
use App\Models\Order;
|
||||
use App\Models\Purchase;
|
||||
|
||||
use function Pest\Laravel\actingAs;
|
||||
use function Pest\Laravel\get;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Analysis Module Tests
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
describe('Analysis Module - Authorization', function () {
|
||||
it('redirects to login when accessing analysis unauthenticated', function () {
|
||||
get(route('analysis'))
|
||||
->assertRedirect(route('login'));
|
||||
});
|
||||
|
||||
it('returns 403 when user has no permission to view analysis', function () {
|
||||
actingAs(createUnauthorizedUser())
|
||||
->get(route('analysis'))
|
||||
->assertStatus(403);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Analysis Module - Authorized Actions', function () {
|
||||
beforeEach(function () {
|
||||
$user = createAuthorizedUser([
|
||||
'View:Analysis',
|
||||
]);
|
||||
actingAs($user);
|
||||
});
|
||||
|
||||
it('can access analysis page and view statistics', function () {
|
||||
// Create dummy data
|
||||
Order::factory()->count(2)->create([
|
||||
'created_at' => now(),
|
||||
'total' => 150000,
|
||||
'cogs' => 75000,
|
||||
]);
|
||||
|
||||
Expense::factory()->create([
|
||||
'created_at' => now(),
|
||||
'amount' => 10000,
|
||||
]);
|
||||
|
||||
Purchase::factory()->create([
|
||||
'created_at' => now(),
|
||||
'total' => 50000,
|
||||
]);
|
||||
|
||||
get(route('analysis'))
|
||||
->assertOk()
|
||||
->assertInertia(fn ($page) => $page
|
||||
->component('analysis')
|
||||
->has('stats')
|
||||
->has('salesByMonth')
|
||||
->has('revenueVsProfit')
|
||||
->has('transactionVolume')
|
||||
->has('salesByHour')
|
||||
->has('paymentMethods')
|
||||
->has('orderStatuses')
|
||||
->has('orderChannels')
|
||||
->has('topProducts')
|
||||
->has('topCustomers')
|
||||
->has('topCategories')
|
||||
);
|
||||
});
|
||||
|
||||
it('can filter analysis by period', function () {
|
||||
get(route('analysis', ['period' => 'month']))
|
||||
->assertOk()
|
||||
->assertInertia(fn ($page) => $page
|
||||
->component('analysis')
|
||||
->has('filters', fn ($f) => $f
|
||||
->where('period', 'month')
|
||||
->where('start_date', null)
|
||||
->where('end_date', null)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('can filter analysis by date range', function () {
|
||||
get(route('analysis', ['start_date' => '2026-01-01', 'end_date' => '2026-01-31']))
|
||||
->assertOk()
|
||||
->assertInertia(fn ($page) => $page
|
||||
->component('analysis')
|
||||
->has('filters', fn ($f) => $f
|
||||
->where('period', 'all')
|
||||
->where('start_date', '2026-01-01')
|
||||
->where('end_date', '2026-01-31')
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user