'ORD-' . uniqid(), 'customer_id' => $customer->id, 'sub_total' => 100_000, 'discount_amount' => 0, 'total' => 100_000, 'status' => OrderStatus::PENDING->value, ]); Invoice::create([ 'invoice_number' => 'INV-' . uniqid(), 'customer_id' => $customer->id, 'order_id' => $order->id, 'invoice_type' => 1, 'sub_total' => 100_000, 'tax' => 0, 'total' => 100_000, 'status' => $invoiceStatus, ]); return $order->fresh(['invoice', 'customer']); } public function test_successful_payment_notifies_admin_once(): void { Bus::fake([AdminPaymentReceivedJob::class]); $customer = Customer::factory()->create(['total' => 200_000]); $order = $this->orderFor($customer, InvoiceStatus::UNPAID->value); app(OrderService::class)->pay($order, 'balance'); Bus::assertDispatchedTimes(AdminPaymentReceivedJob::class, 1); } public function test_insufficient_balance_does_not_notify_admin(): void { Bus::fake([AdminPaymentReceivedJob::class]); $customer = Customer::factory()->create(['total' => 0]); $order = $this->orderFor($customer, InvoiceStatus::UNPAID->value); try { app(OrderService::class)->pay($order, 'balance'); $this->fail('Expected InvalidArgumentException'); } catch (\InvalidArgumentException) { } Bus::assertNotDispatched(AdminPaymentReceivedJob::class); } public function test_paying_an_already_paid_invoice_is_rejected_without_notifying_admin(): void { Bus::fake([AdminPaymentReceivedJob::class]); $customer = Customer::factory()->create(['total' => 200_000]); $order = $this->orderFor($customer, InvoiceStatus::PAID->value); try { app(OrderService::class)->pay($order, 'balance'); $this->fail('Expected InvalidArgumentException'); } catch (\InvalidArgumentException) { } Bus::assertNotDispatched(AdminPaymentReceivedJob::class); $this->assertSame(200_000, (int) $customer->fresh()->total); } }