'Full Administrator', 'guard_name' => 'admin']); $this->admin = User::factory()->create(); $this->admin->assignRole('Full Administrator'); $this->customer = Customer::factory()->create(['total' => 1_000_000]); $this->product = Product::factory()->create(['product_type' => 'hosting']); } private function createService(array $data) { return $this->actingAs($this->admin, 'admin')->postJson( "/api/v1/administrator/customers/{$this->customer->uuid}/services", ['product_id' => $this->product->id, 'server_name' => 'site.vn', 'price' => 500_000, ...$data], ); } public function test_paid_in_full_marks_invoice_paid(): void { $this->createService(['payment_status' => 'paid', 'payment_method' => 'balance'])->assertCreated(); $invoice = Invoice::sole(); $this->assertSame(InvoiceStatus::PAID->value, (int) $invoice->status); $this->assertSame(500_000, (int) $invoice->amount_paid); $this->assertSame(500_000, (int) $this->customer->fresh()->total); } public function test_partial_payment_keeps_invoice_unpaid_with_prepaid_amount(): void { $this->createService(['payment_status' => 'partial', 'payment_method' => 'balance', 'amount_paid' => 200_000])->assertCreated(); $invoice = Invoice::sole(); $this->assertSame(InvoiceStatus::UNPAID->value, (int) $invoice->status); $this->assertSame(500_000, (int) $invoice->total); $this->assertSame(200_000, (int) $invoice->amount_paid); $this->assertSame(200_000, (int) Transaction::sole()->amount); $this->assertSame(800_000, (int) $this->customer->fresh()->total); } public function test_service_detail_lists_every_payment_installment_of_an_invoice(): void { $serviceId = $this->createService(['payment_status' => 'partial', 'payment_method' => 'balance', 'amount_paid' => 200_000]) ->assertCreated() ->json('data.id'); $invoice = Invoice::sole(); $admin = $this->actingAs($this->admin, 'admin'); $admin->postJson("/api/v1/administrator/invoices/{$invoice->id}/paid", ['received_amount' => 100_000])->assertOk(); $admin->postJson("/api/v1/administrator/invoices/{$invoice->id}/paid", ['note' => 'Đợt cuối'])->assertOk(); $payments = $admin->getJson("/api/v1/administrator/services/{$serviceId}") ->assertOk() ->json('data.linked_invoices.0.payments'); $this->assertSame([200_000, 100_000, 200_000], array_column($payments, 'amount')); $this->assertSame(InvoiceStatus::PAID->value, (int) $invoice->fresh()->status); } public function test_decimal_amounts_are_rounded_to_whole_dong(): void { $this->createService(['price' => 731.33, 'payment_status' => 'partial', 'payment_method' => 'balance', 'amount_paid' => 400.6])->assertCreated(); $invoice = Invoice::sole(); $this->assertSame(731, (int) $invoice->total); $this->assertSame(401, (int) $invoice->amount_paid); } public function test_partial_payment_must_be_less_than_price(): void { $this->createService(['payment_status' => 'partial', 'payment_method' => 'balance', 'amount_paid' => 500_000])->assertStatus(422); $this->createService(['payment_status' => 'partial', 'payment_method' => 'balance'])->assertStatus(422); $this->assertSame(0, Invoice::count()); } public function test_unpaid_creates_unpaid_invoice_without_transaction(): void { $this->createService(['payment_status' => 'unpaid'])->assertCreated(); $invoice = Invoice::sole(); $this->assertSame(InvoiceStatus::UNPAID->value, (int) $invoice->status); $this->assertSame(0, (int) $invoice->amount_paid); $this->assertSame(0, Transaction::count()); $this->assertSame(1_000_000, (int) $this->customer->fresh()->total); } }