diff --git a/Taskfile.yml b/Taskfile.yml index eca8299..bbec907 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -22,10 +22,10 @@ tasks: db:seed: desc: Seed the Billing module database - cmd: php artisan modules:seed --module=billing + cmd: '{{.APP}} php artisan modules:seed --module=billing' # ── Code Generation ──────────────────────────────────────────── types:generate: desc: Generate TypeScript types from PHP DTOs and enums - cmd: php artisan module:generate-types billing + cmd: '{{.APP}} php artisan module:generate-types billing' diff --git a/src/Filament/Widgets/ConversionChartWidget.php b/src/Filament/Widgets/ConversionChartWidget.php index 44d9c29..e210af4 100644 --- a/src/Filament/Widgets/ConversionChartWidget.php +++ b/src/Filament/Widgets/ConversionChartWidget.php @@ -77,27 +77,31 @@ protected function getData(): array { $buckets = $this->buildMonthlyBuckets(); - $rows = CheckoutSession::whereBetween('created_at', [$this->startDate, $this->endDate]) - ->whereIn('status', [ - CheckoutSessionStatus::Completed->value, - CheckoutSessionStatus::Abandoned->value, - CheckoutSessionStatus::Expired->value, - ]) - ->selectRaw( - 'DATE_FORMAT(created_at, "%Y-%m") as month, SUM(status = ?) as completed, COUNT(*) as total', - [CheckoutSessionStatus::Completed->value] - ) - ->groupBy('month') - ->orderBy('month') - ->get(); - - foreach ($rows as $row) { - $month = (string) $row->getAttribute('month'); - $total = (int) $row->getAttribute('total'); - $completed = (int) $row->getAttribute('completed'); - if (array_key_exists($month, $buckets) && $total > 0) { - $buckets[$month] = round($completed / $total * 100, 1); + try { + $rows = CheckoutSession::whereBetween('created_at', [$this->startDate, $this->endDate]) + ->whereIn('status', [ + CheckoutSessionStatus::Completed->value, + CheckoutSessionStatus::Abandoned->value, + CheckoutSessionStatus::Expired->value, + ]) + ->selectRaw( + 'DATE_FORMAT(created_at, "%Y-%m") as month, SUM(status = ?) as completed, COUNT(*) as total', + [CheckoutSessionStatus::Completed->value] + ) + ->groupBy('month') + ->orderBy('month') + ->get(); + + foreach ($rows as $row) { + $month = (string) $row->getAttribute('month'); + $total = (int) $row->getAttribute('total'); + $completed = (int) $row->getAttribute('completed'); + if (array_key_exists($month, $buckets) && $total > 0) { + $buckets[$month] = round($completed / $total * 100, 1); + } } + } catch (\Throwable $e) { + report($e); } $labels = array_map( diff --git a/src/Filament/Widgets/RevenueChartWidget.php b/src/Filament/Widgets/RevenueChartWidget.php index 6ced768..d278d0c 100644 --- a/src/Filament/Widgets/RevenueChartWidget.php +++ b/src/Filament/Widgets/RevenueChartWidget.php @@ -59,18 +59,22 @@ protected function getData(): array { $buckets = $this->buildMonthlyBuckets(); - $rows = Payment::where('status', PaymentStatus::Succeeded) - ->whereBetween('created_at', [$this->startDate, $this->endDate]) - ->selectRaw('DATE_FORMAT(created_at, "%Y-%m") as month, SUM(amount) as total') - ->groupBy('month') - ->orderBy('month') - ->get(); - - foreach ($rows as $row) { - $month = (string) $row->getAttribute('month'); - if (array_key_exists($month, $buckets)) { - $buckets[$month] = (int) $row->getAttribute('total'); + try { + $rows = Payment::where('status', PaymentStatus::Succeeded) + ->whereBetween('created_at', [$this->startDate, $this->endDate]) + ->selectRaw('DATE_FORMAT(created_at, "%Y-%m") as month, SUM(amount) as total') + ->groupBy('month') + ->orderBy('month') + ->get(); + + foreach ($rows as $row) { + $month = (string) $row->getAttribute('month'); + if (array_key_exists($month, $buckets)) { + $buckets[$month] = (int) $row->getAttribute('total'); + } } + } catch (\Throwable $e) { + report($e); } $labels = array_map( diff --git a/src/Filament/Widgets/SubscriptionsChartWidget.php b/src/Filament/Widgets/SubscriptionsChartWidget.php index edaa037..45c08d2 100644 --- a/src/Filament/Widgets/SubscriptionsChartWidget.php +++ b/src/Filament/Widgets/SubscriptionsChartWidget.php @@ -58,17 +58,21 @@ protected function getData(): array { $buckets = $this->buildMonthlyBuckets(); - $rows = Subscription::whereBetween('created_at', [$this->startDate, $this->endDate]) - ->selectRaw('DATE_FORMAT(created_at, "%Y-%m") as month, COUNT(*) as total') - ->groupBy('month') - ->orderBy('month') - ->get(); - - foreach ($rows as $row) { - $month = (string) $row->getAttribute('month'); - if (array_key_exists($month, $buckets)) { - $buckets[$month] = (int) $row->getAttribute('total'); + try { + $rows = Subscription::whereBetween('created_at', [$this->startDate, $this->endDate]) + ->selectRaw('DATE_FORMAT(created_at, "%Y-%m") as month, COUNT(*) as total') + ->groupBy('month') + ->orderBy('month') + ->get(); + + foreach ($rows as $row) { + $month = (string) $row->getAttribute('month'); + if (array_key_exists($month, $buckets)) { + $buckets[$month] = (int) $row->getAttribute('total'); + } } + } catch (\Throwable $e) { + report($e); } $labels = array_map( diff --git a/tests/Feature/BillingServiceTest.php b/tests/Feature/BillingServiceTest.php index b2ccf25..5a1301a 100644 --- a/tests/Feature/BillingServiceTest.php +++ b/tests/Feature/BillingServiceTest.php @@ -65,9 +65,9 @@ protected function setUp(): void $manager = $this->createMock(PaymentGatewayManager::class); $manager->method('driver')->willReturn($this->gateway); - $this->app->instance(PaymentGatewayManager::class, $manager); + app()->instance(PaymentGatewayManager::class, $manager); - $this->billingService = $this->app->make(BillingService::class); + $this->billingService = app()->make(BillingService::class); } public function test_process_checkout_creates_customer(): void diff --git a/tests/Feature/CheckoutControllerTest.php b/tests/Feature/CheckoutControllerTest.php index 0bc53d9..75766b4 100644 --- a/tests/Feature/CheckoutControllerTest.php +++ b/tests/Feature/CheckoutControllerTest.php @@ -47,7 +47,7 @@ protected function setUp(): void $manager = $this->createMock(PaymentGatewayManager::class); $manager->method('driver')->willReturn($gateway); - $this->app->instance(PaymentGatewayManager::class, $manager); + app()->instance(PaymentGatewayManager::class, $manager); } public function test_checkout_requires_authentication(): void diff --git a/tests/Feature/CheckoutSessionValidationTest.php b/tests/Feature/CheckoutSessionValidationTest.php index daee80b..4e0e773 100644 --- a/tests/Feature/CheckoutSessionValidationTest.php +++ b/tests/Feature/CheckoutSessionValidationTest.php @@ -38,7 +38,7 @@ protected function setUp(): void $manager = $this->createMock(PaymentGatewayManager::class); $manager->method('driver')->willReturn($gateway); - $this->app->instance(PaymentGatewayManager::class, $manager); + app()->instance(PaymentGatewayManager::class, $manager); } public function test_show_rejects_expired_checkout_session(): void diff --git a/tests/Feature/DatabaseSeederTest.php b/tests/Feature/DatabaseSeederTest.php index e335f6a..9b0679a 100644 --- a/tests/Feature/DatabaseSeederTest.php +++ b/tests/Feature/DatabaseSeederTest.php @@ -12,8 +12,8 @@ class DatabaseSeederTest extends TestCase public function test_module_database_seeder_runs(): void { - $this->seed(DatabaseSeeder::class); + $this->expectNotToPerformAssertions(); - $this->assertTrue(true); + $this->seed(DatabaseSeeder::class); } } diff --git a/tests/Feature/SubscriptionCancelTest.php b/tests/Feature/SubscriptionCancelTest.php index d4e9719..4e2ace8 100644 --- a/tests/Feature/SubscriptionCancelTest.php +++ b/tests/Feature/SubscriptionCancelTest.php @@ -26,7 +26,7 @@ protected function setUp(): void $manager = $this->createMock(PaymentGatewayManager::class); $manager->method('driver')->willReturn($this->gateway); - $this->app->instance(PaymentGatewayManager::class, $manager); + app()->instance(PaymentGatewayManager::class, $manager); } public function test_cancel_subscription_requires_auth(): void diff --git a/tests/Feature/SubscriptionResumeTest.php b/tests/Feature/SubscriptionResumeTest.php index a57dc2c..7b5e8ea 100644 --- a/tests/Feature/SubscriptionResumeTest.php +++ b/tests/Feature/SubscriptionResumeTest.php @@ -26,7 +26,7 @@ protected function setUp(): void $manager = $this->createMock(PaymentGatewayManager::class); $manager->method('driver')->willReturn($this->gateway); - $this->app->instance(PaymentGatewayManager::class, $manager); + app()->instance(PaymentGatewayManager::class, $manager); } public function test_resume_subscription_requires_auth(): void diff --git a/tests/Feature/WebhookIdempotencyTest.php b/tests/Feature/WebhookIdempotencyTest.php index 394d148..47c96ff 100644 --- a/tests/Feature/WebhookIdempotencyTest.php +++ b/tests/Feature/WebhookIdempotencyTest.php @@ -54,9 +54,9 @@ protected function setUp(): void $manager = $this->createMock(PaymentGatewayManager::class); $manager->method('driver')->willReturn($this->gateway); - $this->app->instance(PaymentGatewayManager::class, $manager); + app()->instance(PaymentGatewayManager::class, $manager); - $this->billingService = $this->app->make(BillingService::class); + $this->billingService = app()->make(BillingService::class); } public function test_duplicate_webhook_event_is_skipped(): void diff --git a/tests/Support/BillingTestHelper.php b/tests/Support/BillingTestHelper.php index b26c384..1e9b8fe 100644 --- a/tests/Support/BillingTestHelper.php +++ b/tests/Support/BillingTestHelper.php @@ -31,7 +31,7 @@ public static function createSubscriberFixtures(): void // --- Active subscriber --- $subscriber = User::firstOrCreate( ['email' => 'subscriber@example.com'], - ['name' => 'Subscriber User', 'password' => Hash::make('secretsauce'), 'email_verified_at' => now()], + ['name' => 'Subscriber User', 'password' => Hash::make('password'), 'email_verified_at' => now()], ); $subscriber->assignRole('user'); @@ -56,7 +56,7 @@ public static function createSubscriberFixtures(): void // --- Cancelled subscriber (pending cancellation) --- $cancelled = User::firstOrCreate( ['email' => 'cancelled@example.com'], - ['name' => 'Cancelled User', 'password' => Hash::make('secretsauce'), 'email_verified_at' => now()], + ['name' => 'Cancelled User', 'password' => Hash::make('password'), 'email_verified_at' => now()], ); $cancelled->assignRole('user');