'finance_accountant']); Role::create(['name' => 'finance_cashier']); $this->accountant = User::factory()->create(['email' => 'accountant@test.com']); $this->cashier = User::factory()->create(['email' => 'cashier@test.com']); $this->accountant->assignRole('finance_accountant'); $this->cashier->assignRole('finance_cashier'); $this->accountant->givePermissionTo(['create_payment_order', 'view_payment_orders']); $this->cashier->givePermissionTo(['verify_payment_order', 'execute_payment', 'view_payment_orders']); // Create an approved finance document $this->approvedDocument = FinanceDocument::create([ 'title' => 'Approved Document', 'description' => 'Test', 'amount' => 5000, 'request_type' => 'expense_reimbursement', 'status' => FinanceDocument::STATUS_APPROVED_ACCOUNTANT, 'submitted_by_id' => $this->accountant->id, 'submitted_at' => now(), 'cashier_approved_at' => now(), 'accountant_approved_at' => now(), 'amount_tier' => 'small', ]); } /** @test */ public function accountant_can_create_payment_order_for_approved_document() { $this->actingAs($this->accountant); $response = $this->post(route('admin.payment-orders.store'), [ 'finance_document_id' => $this->approvedDocument->id, 'payee_name' => 'John Doe', 'payment_amount' => 5000, 'payment_method' => 'bank_transfer', 'payee_bank_name' => 'Test Bank', 'payee_bank_code' => '012', 'payee_account_number' => '1234567890', 'notes' => 'Test payment order', ]); $response->assertRedirect(); $this->assertDatabaseHas('payment_orders', [ 'finance_document_id' => $this->approvedDocument->id, 'payee_name' => 'John Doe', 'payment_amount' => 5000, 'status' => 'pending_verification', ]); // Check finance document is updated $this->approvedDocument->refresh(); $this->assertNotNull($this->approvedDocument->payment_order_created_at); } /** @test */ public function payment_order_number_is_automatically_generated() { $paymentOrder = PaymentOrder::create([ 'finance_document_id' => $this->approvedDocument->id, 'payment_order_number' => PaymentOrder::generatePaymentOrderNumber(), 'payee_name' => 'Test Payee', 'payment_amount' => 5000, 'payment_method' => 'cash', 'status' => 'pending_verification', 'created_by_accountant_id' => $this->accountant->id, ]); $this->assertNotEmpty($paymentOrder->payment_order_number); $this->assertStringStartsWith('PO-', $paymentOrder->payment_order_number); } /** @test */ public function cashier_can_verify_payment_order() { $paymentOrder = PaymentOrder::create([ 'finance_document_id' => $this->approvedDocument->id, 'payment_order_number' => PaymentOrder::generatePaymentOrderNumber(), 'payee_name' => 'Test Payee', 'payment_amount' => 5000, 'payment_method' => 'cash', 'status' => 'pending_verification', 'created_by_accountant_id' => $this->accountant->id, ]); $this->actingAs($this->cashier); $response = $this->post(route('admin.payment-orders.verify', $paymentOrder), [ 'action' => 'approve', 'verification_notes' => 'Verified and approved', ]); $response->assertRedirect(); $paymentOrder->refresh(); $this->assertEquals('approved', $paymentOrder->verification_status); $this->assertEquals('verified', $paymentOrder->status); $this->assertNotNull($paymentOrder->verified_at); $this->assertEquals($this->cashier->id, $paymentOrder->verified_by_cashier_id); // Check finance document is updated $this->approvedDocument->refresh(); $this->assertNotNull($this->approvedDocument->payment_verified_at); } /** @test */ public function cashier_can_reject_payment_order_during_verification() { $paymentOrder = PaymentOrder::create([ 'finance_document_id' => $this->approvedDocument->id, 'payment_order_number' => PaymentOrder::generatePaymentOrderNumber(), 'payee_name' => 'Test Payee', 'payment_amount' => 5000, 'payment_method' => 'cash', 'status' => 'pending_verification', 'created_by_accountant_id' => $this->accountant->id, ]); $this->actingAs($this->cashier); $response = $this->post(route('admin.payment-orders.verify', $paymentOrder), [ 'action' => 'reject', 'verification_notes' => 'Incorrect amount', ]); $response->assertRedirect(); $paymentOrder->refresh(); $this->assertEquals('rejected', $paymentOrder->verification_status); $this->assertNotNull($paymentOrder->verified_at); } /** @test */ public function cashier_can_execute_verified_payment_order() { Storage::fake('local'); $paymentOrder = PaymentOrder::create([ 'finance_document_id' => $this->approvedDocument->id, 'payment_order_number' => PaymentOrder::generatePaymentOrderNumber(), 'payee_name' => 'Test Payee', 'payment_amount' => 5000, 'payment_method' => 'bank_transfer', 'status' => 'verified', 'verification_status' => 'approved', 'created_by_accountant_id' => $this->accountant->id, 'verified_by_cashier_id' => $this->cashier->id, 'verified_at' => now(), ]); $this->actingAs($this->cashier); $receipt = UploadedFile::fake()->create('receipt.pdf', 100); $response = $this->post(route('admin.payment-orders.execute', $paymentOrder), [ 'transaction_reference' => 'TXN123456', 'payment_receipt' => $receipt, 'execution_notes' => 'Payment completed successfully', ]); $response->assertRedirect(); $paymentOrder->refresh(); $this->assertEquals('executed', $paymentOrder->status); $this->assertEquals('completed', $paymentOrder->execution_status); $this->assertNotNull($paymentOrder->executed_at); $this->assertEquals($this->cashier->id, $paymentOrder->executed_by_cashier_id); $this->assertEquals('TXN123456', $paymentOrder->transaction_reference); // Check finance document is updated $this->approvedDocument->refresh(); $this->assertNotNull($this->approvedDocument->payment_executed_at); } /** @test */ public function cannot_execute_unverified_payment_order() { $paymentOrder = PaymentOrder::create([ 'finance_document_id' => $this->approvedDocument->id, 'payment_order_number' => PaymentOrder::generatePaymentOrderNumber(), 'payee_name' => 'Test Payee', 'payment_amount' => 5000, 'payment_method' => 'cash', 'status' => 'pending_verification', 'created_by_accountant_id' => $this->accountant->id, ]); $this->assertFalse($paymentOrder->canBeExecuted()); } /** @test */ public function cannot_verify_already_verified_payment_order() { $paymentOrder = PaymentOrder::create([ 'finance_document_id' => $this->approvedDocument->id, 'payment_order_number' => PaymentOrder::generatePaymentOrderNumber(), 'payee_name' => 'Test Payee', 'payment_amount' => 5000, 'payment_method' => 'cash', 'status' => 'verified', 'verification_status' => 'approved', 'created_by_accountant_id' => $this->accountant->id, 'verified_by_cashier_id' => $this->cashier->id, 'verified_at' => now(), ]); $this->assertFalse($paymentOrder->canBeVerifiedByCashier()); } /** @test */ public function accountant_can_cancel_unexecuted_payment_order() { $paymentOrder = PaymentOrder::create([ 'finance_document_id' => $this->approvedDocument->id, 'payment_order_number' => PaymentOrder::generatePaymentOrderNumber(), 'payee_name' => 'Test Payee', 'payment_amount' => 5000, 'payment_method' => 'cash', 'status' => 'pending_verification', 'created_by_accountant_id' => $this->accountant->id, ]); $this->actingAs($this->accountant); $response = $this->post(route('admin.payment-orders.cancel', $paymentOrder)); $response->assertRedirect(); $paymentOrder->refresh(); $this->assertEquals('cancelled', $paymentOrder->status); } /** @test */ public function payment_order_for_different_payment_methods() { // Test cash payment $cashOrder = PaymentOrder::create([ 'finance_document_id' => $this->approvedDocument->id, 'payment_order_number' => PaymentOrder::generatePaymentOrderNumber(), 'payee_name' => 'Test Payee', 'payment_amount' => 1000, 'payment_method' => 'cash', 'status' => 'pending_verification', 'created_by_accountant_id' => $this->accountant->id, ]); $this->assertEquals('現金', $cashOrder->getPaymentMethodText()); // Test check payment $checkOrder = PaymentOrder::create([ 'finance_document_id' => $this->approvedDocument->id, 'payment_order_number' => PaymentOrder::generatePaymentOrderNumber(), 'payee_name' => 'Test Payee', 'payment_amount' => 2000, 'payment_method' => 'check', 'status' => 'pending_verification', 'created_by_accountant_id' => $this->accountant->id, ]); $this->assertEquals('支票', $checkOrder->getPaymentMethodText()); // Test bank transfer $transferOrder = PaymentOrder::create([ 'finance_document_id' => $this->approvedDocument->id, 'payment_order_number' => PaymentOrder::generatePaymentOrderNumber(), 'payee_name' => 'Test Payee', 'payment_amount' => 3000, 'payment_method' => 'bank_transfer', 'payee_bank_name' => 'Test Bank', 'payee_bank_code' => '012', 'payee_account_number' => '1234567890', 'status' => 'pending_verification', 'created_by_accountant_id' => $this->accountant->id, ]); $this->assertEquals('銀行轉帳', $transferOrder->getPaymentMethodText()); } }