create($attributes); } /** * Create a small amount finance document (< 5000) */ protected function createSmallAmountDocument(array $attributes = []): FinanceDocument { $doc = $this->createFinanceDocument(array_merge([ 'amount' => 3000, ], $attributes)); // Verify it's small amount assert($doc->determineAmountTier() === FinanceDocument::AMOUNT_TIER_SMALL); return $doc; } /** * Create a medium amount finance document (5000 - 50000) */ protected function createMediumAmountDocument(array $attributes = []): FinanceDocument { $doc = $this->createFinanceDocument(array_merge([ 'amount' => 25000, ], $attributes)); // Verify it's medium amount assert($doc->determineAmountTier() === FinanceDocument::AMOUNT_TIER_MEDIUM); return $doc; } /** * Create a large amount finance document (> 50000) */ protected function createLargeAmountDocument(array $attributes = []): FinanceDocument { $doc = $this->createFinanceDocument(array_merge([ 'amount' => 75000, ], $attributes)); // Verify it's large amount assert($doc->determineAmountTier() === FinanceDocument::AMOUNT_TIER_LARGE); return $doc; } /** * Create a finance document at specific approval stage */ protected function createDocumentAtStage(string $stage, array $attributes = []): FinanceDocument { $statusMap = [ 'pending' => FinanceDocument::STATUS_PENDING, 'cashier_approved' => FinanceDocument::STATUS_APPROVED_CASHIER, 'accountant_approved' => FinanceDocument::STATUS_APPROVED_ACCOUNTANT, 'chair_approved' => FinanceDocument::STATUS_APPROVED_CHAIR, 'rejected' => FinanceDocument::STATUS_REJECTED, ]; return $this->createFinanceDocument(array_merge([ 'status' => $statusMap[$stage] ?? FinanceDocument::STATUS_PENDING, ], $attributes)); } /** * Create a payment order */ protected function createPaymentOrder(array $attributes = []): PaymentOrder { if (!isset($attributes['finance_document_id'])) { $document = $this->createDocumentAtStage('chair_approved'); $attributes['finance_document_id'] = $document->id; } return PaymentOrder::factory()->create($attributes); } /** * Create a payment order at specific stage */ protected function createPaymentOrderAtStage(string $stage, array $attributes = []): PaymentOrder { $statusMap = [ 'draft' => PaymentOrder::STATUS_DRAFT, 'pending_verification' => PaymentOrder::STATUS_PENDING_VERIFICATION, 'verified' => PaymentOrder::STATUS_VERIFIED, 'executed' => PaymentOrder::STATUS_EXECUTED, 'cancelled' => PaymentOrder::STATUS_CANCELLED, ]; return $this->createPaymentOrder(array_merge([ 'status' => $statusMap[$stage] ?? PaymentOrder::STATUS_DRAFT, ], $attributes)); } /** * Create a cashier ledger entry */ protected function createCashierLedgerEntry(array $attributes = []): CashierLedgerEntry { $cashier = $attributes['recorded_by_cashier_id'] ?? User::factory()->create()->id; return CashierLedgerEntry::create(array_merge([ 'entry_type' => 'receipt', 'entry_date' => now(), 'amount' => 10000, 'payment_method' => 'bank_transfer', 'bank_account' => 'Test Bank Account', 'balance_before' => 0, 'balance_after' => 10000, 'recorded_by_cashier_id' => $cashier, 'recorded_at' => now(), ], $attributes)); } /** * Create a receipt entry (income) */ protected function createReceiptEntry(int $amount, string $bankAccount = 'Test Account', array $attributes = []): CashierLedgerEntry { $latestBalance = CashierLedgerEntry::getLatestBalance($bankAccount); return $this->createCashierLedgerEntry(array_merge([ 'entry_type' => 'receipt', 'amount' => $amount, 'bank_account' => $bankAccount, 'balance_before' => $latestBalance, 'balance_after' => $latestBalance + $amount, ], $attributes)); } /** * Create a payment entry (expense) */ protected function createPaymentEntry(int $amount, string $bankAccount = 'Test Account', array $attributes = []): CashierLedgerEntry { $latestBalance = CashierLedgerEntry::getLatestBalance($bankAccount); return $this->createCashierLedgerEntry(array_merge([ 'entry_type' => 'payment', 'amount' => $amount, 'bank_account' => $bankAccount, 'balance_before' => $latestBalance, 'balance_after' => $latestBalance - $amount, ], $attributes)); } /** * Create a bank reconciliation */ protected function createBankReconciliation(array $attributes = []): BankReconciliation { $cashier = $attributes['prepared_by_cashier_id'] ?? User::factory()->create()->id; return BankReconciliation::create(array_merge([ 'reconciliation_month' => now()->startOfMonth(), 'bank_statement_date' => now(), 'bank_statement_balance' => 100000, 'system_book_balance' => 100000, 'outstanding_checks' => [], 'deposits_in_transit' => [], 'bank_charges' => [], 'prepared_by_cashier_id' => $cashier, 'prepared_at' => now(), 'reconciliation_status' => 'pending', 'discrepancy_amount' => 0, ], $attributes)); } /** * Create a bank reconciliation with discrepancy */ protected function createReconciliationWithDiscrepancy(int $discrepancy, array $attributes = []): BankReconciliation { return $this->createBankReconciliation(array_merge([ 'bank_statement_balance' => 100000, 'system_book_balance' => 100000 - $discrepancy, 'discrepancy_amount' => $discrepancy, 'reconciliation_status' => 'discrepancy', ], $attributes)); } /** * Create a completed bank reconciliation */ protected function createCompletedReconciliation(array $attributes = []): BankReconciliation { $cashier = User::factory()->create(); $accountant = User::factory()->create(); $manager = User::factory()->create(); return $this->createBankReconciliation(array_merge([ 'prepared_by_cashier_id' => $cashier->id, 'prepared_at' => now()->subDays(3), 'reviewed_by_accountant_id' => $accountant->id, 'reviewed_at' => now()->subDays(2), 'approved_by_manager_id' => $manager->id, 'approved_at' => now()->subDay(), 'reconciliation_status' => 'completed', ], $attributes)); } /** * Create a budget */ protected function createBudget(array $attributes = []): Budget { return Budget::factory()->create($attributes); } /** * Create a budget with items */ protected function createBudgetWithItems(int $itemCount = 3, array $budgetAttributes = []): Budget { $budget = $this->createBudget($budgetAttributes); for ($i = 0; $i < $itemCount; $i++) { $account = ChartOfAccount::factory()->create(); BudgetItem::factory()->create([ 'budget_id' => $budget->id, 'chart_of_account_id' => $account->id, 'budgeted_amount' => rand(10000, 50000), ]); } return $budget->fresh('items'); } /** * Create a fake attachment file */ protected function createFakeAttachment(string $name = 'document.pdf'): UploadedFile { return UploadedFile::fake()->create($name, 100, 'application/pdf'); } /** * Get valid finance document data */ protected function getValidFinanceDocumentData(array $overrides = []): array { return array_merge([ 'title' => 'Test Finance Document', 'description' => 'Test description', 'amount' => 10000, 'request_type' => FinanceDocument::REQUEST_TYPE_EXPENSE_REIMBURSEMENT, 'payee_name' => 'Test Payee', 'notes' => 'Test notes', ], $overrides); } }