procurementService = $procurementService; } public function getAccountingReportData(string $start, string $end): array { // 1. 獲取應付帳款資料 (已付款) $accountPayables = \App\Modules\Finance\Models\AccountPayable::where('status', \App\Modules\Finance\Models\AccountPayable::STATUS_PAID) ->whereNotNull('paid_at') ->whereBetween('paid_at', [$start, $end]) ->get(); // 取得供應商資料 (Manual Hydration) $vendorIds = $accountPayables->pluck('vendor_id')->unique()->filter()->toArray(); $vendorsMap = $this->procurementService->getVendorsByIds($vendorIds)->keyBy('id'); // 付款方式對映 $paymentMethodMap = [ 'cash' => '現金', 'bank_transfer' => '銀行轉帳', 'check' => '支票', 'credit_card' => '信用卡', ]; $payableRecords = $accountPayables->map(function ($ap) use ($vendorsMap, $paymentMethodMap) { $vendorName = isset($vendorsMap[$ap->vendor_id]) ? $vendorsMap[$ap->vendor_id]->name : '未知廠商'; $mappedPaymentMethod = $paymentMethodMap[$ap->payment_method] ?? $ap->payment_method; return [ 'id' => 'AP-' . $ap->id, 'date' => Carbon::parse($ap->paid_at)->timezone(config('app.timezone'))->toDateString(), 'source' => '應付帳款', 'category' => '進貨支出', 'item' => $vendorName, 'reference' => $ap->document_number, 'invoice_date' => $ap->invoice_date ? $ap->invoice_date->format('Y-m-d') : null, 'invoice_number' => $ap->invoice_number, 'amount' => (float)$ap->total_amount, 'tax_amount' => (float)$ap->tax_amount, 'status' => $ap->status, 'payment_method' => $mappedPaymentMethod, 'payment_note' => $ap->payment_note, 'remarks' => $ap->remarks, ]; }); // 2. 獲取公共事業費 (已繳費) $utilityFees = UtilityFee::where('payment_status', UtilityFee::STATUS_PAID) ->whereBetween('transaction_date', [$start, $end]) ->get() ->map(function ($fee) { return [ 'id' => 'UF-' . $fee->id, 'date' => $fee->transaction_date->format('Y-m-d'), 'source' => '公共事業費', 'category' => $fee->category, 'item' => $fee->description ?: $fee->category, 'reference' => '-', 'invoice_date' => null, 'invoice_number' => $fee->invoice_number, 'amount' => (float)$fee->amount, 'tax_amount' => 0.0, 'status' => $fee->payment_status, 'payment_method' => null, 'payment_note' => null, 'remarks' => $fee->description, ]; }); $allRecords = $payableRecords->concat($utilityFees) ->sortByDesc('date') ->values(); return [ 'records' => $allRecords, 'summary' => [ 'total_amount' => $allRecords->sum('amount'), 'payable_total' => $payableRecords->sum('amount'), 'utility_total' => $utilityFees->sum('amount'), 'record_count' => $allRecords->count(), ] ]; } public function getUtilityFees(array $filters) { $query = UtilityFee::withCount('attachments'); if (!empty($filters['search'])) { $search = $filters['search']; $query->where(function($q) use ($search) { $q->where('category', 'like', "%{$search}%") ->orWhere('invoice_number', 'like', "%{$search}%") ->orWhere('description', 'like', "%{$search}%"); }); } if (!empty($filters['category']) && $filters['category'] !== 'all') { $query->where('category', $filters['category']); } if (!empty($filters['date_start'])) { $query->where('transaction_date', '>=', $filters['date_start']); } if (!empty($filters['date_end'])) { $query->where('transaction_date', '<=', $filters['date_end']); } $sortField = $filters['sort_field'] ?? 'created_at'; $sortDirection = $filters['sort_direction'] ?? 'desc'; $query->orderBy($sortField, $sortDirection); $defaultPerPage = \App\Modules\Core\Models\SystemSetting::getVal('display.per_page', 10); $perPage = (int) ($filters['per_page'] ?? $defaultPerPage); if (!in_array($perPage, [10, 20, 50, 100])) { $perPage = $defaultPerPage; } return $query->paginate($perPage); } public function getUniqueCategories(): Collection { return UtilityFee::distinct()->pluck('category'); } }