orderByRequest($bills, $request); // Filter $this->filterRequest( builder: $bills, request: $request, filterKeys: [ 'billing_date' => self::F_TEXT, ] ); // Search $this->searchRequest( builder: $bills, value: $request->get('search'), fields: ['billing_date', 'notes'] ); $responseData = $bills ->leftJoin('users as creator', 'electricity_bills.created_by', '=', 'creator.id') ->leftJoin('users as updater', 'electricity_bills.updated_by', '=', 'updater.id') ->orderBy('electricity_bills.billing_date', 'desc') ->select( 'electricity_bills.*', 'creator.name as creator_name', 'updater.name as updater_name' ) ->paginate($request->get('per_page', 15)); return AbstractController::ResultSuccess($responseData); } catch (\Exception $e) { Log::error('Error fetching electricity bills: ' . $e->getMessage()); return AbstractController::ResultError($e->getMessage()); } } /** * Create new electricity bill */ public function create(Request $request) { try { $validated = $request->validate([ 'billing_date' => 'required|string', 'previous_reading' => 'required|numeric|min:0', 'current_reading' => 'required|numeric|min:0', 'unit_price' => 'required|numeric|min:0', 'notes' => 'nullable|string', ]); // Check if billing_date already exists $existingBill = ElectricityBill::where('billing_date', $validated['billing_date'])->first(); if ($existingBill) { return AbstractController::ResultError('Bill for this month already exists', 422); } // Calculate total amount $consumption = $validated['current_reading'] - $validated['previous_reading']; $totalAmount = $consumption * $validated['unit_price']; $bill = ElectricityBill::create([ 'billing_date' => $validated['billing_date'], 'previous_reading' => $validated['previous_reading'], 'current_reading' => $validated['current_reading'], 'unit_price' => $validated['unit_price'], 'total_amount' => $totalAmount, 'notes' => $validated['notes'] ?? null, 'created_by' => auth('admins')->user()->id ?? null, ]); return AbstractController::ResultSuccess($bill, 'Electricity bill created successfully'); } catch (\Exception $e) { Log::error('Error creating electricity bill: ' . $e->getMessage()); return AbstractController::ResultError($e->getMessage()); } } /** * Update electricity bill */ public function update(Request $request, $id) { try { $validated = $request->validate([ 'billing_date' => 'sometimes|string', 'previous_reading' => 'sometimes|numeric|min:0', 'current_reading' => 'sometimes|numeric|min:0', 'unit_price' => 'sometimes|numeric|min:0', 'notes' => 'nullable|string', ]); $bill = ElectricityBill::findOrFail($id); // Check if billing_date already exists (excluding current record) if (isset($validated['billing_date'])) { $existingBill = ElectricityBill::where('billing_date', $validated['billing_date']) ->where('id', '!=', $id) ->first(); if ($existingBill) { return AbstractController::ResultError('Bill for this month already exists', 422); } } // Recalculate total if any reading or price changed $previousReading = $validated['previous_reading'] ?? $bill->previous_reading; $currentReading = $validated['current_reading'] ?? $bill->current_reading; $unitPrice = $validated['unit_price'] ?? $bill->unit_price; $consumption = $currentReading - $previousReading; $totalAmount = $consumption * $unitPrice; $bill->update(array_merge($validated, [ 'total_amount' => $totalAmount, 'updated_by' => auth('admins')->user()->id ?? null, ])); return AbstractController::ResultSuccess($bill, 'Electricity bill updated successfully'); } catch (\Exception $e) { Log::error('Error updating electricity bill: ' . $e->getMessage()); return AbstractController::ResultError($e->getMessage()); } } /** * Delete electricity bill */ public function delete(Request $request, $id) { try { $bill = ElectricityBill::findOrFail($id); $bill->delete(); return AbstractController::ResultSuccess(null, 'Electricity bill deleted successfully'); } catch (\Exception $e) { Log::error('Error deleting electricity bill: ' . $e->getMessage()); return AbstractController::ResultError($e->getMessage()); } } /** * Export electricity bill to PDF */ public function exportPdf(Request $request, $id) { try { $bill = ElectricityBill::findOrFail($id); // Get month name from billing_date $consumption = $bill->current_reading - $bill->previous_reading; $totalText = $this->numberToVietnamese($bill->total_amount); $date = Carbon::parse($bill->billing_date); $dateNow = 'Ngày ' . $date->day . ' tháng ' . $date->month . ' năm ' . $date->year; // Generate PDF $pdf = Pdf::loadView('admin::admin.electricity_bills.pdf', [ 'bill' => $bill, 'consumption' => $consumption, 'dateNow' => $dateNow, 'totalText' => $totalText ]); $fileName = 'electricity_bill_' . $bill->billing_date . '.pdf'; $filePath = 'electricity_bills/' . $fileName; // đảm bảo folder tồn tại if (!Storage::disk('public')->exists('electricity_bills')) { Storage::disk('public')->makeDirectory('electricity_bills'); } // 👇 render 1 lần $pdfContent = $pdf->output(); // 👇 lưu file Storage::disk('public')->put($filePath, $pdfContent); // update DB $bill->update(['file_path' => $filePath]); // 👇 trả về đúng file đã tạo return response($pdfContent) ->header('Content-Type', 'application/pdf') ->header('Content-Disposition', 'attachment; filename="' . $fileName . '"'); } catch (\Exception $e) { Log::error('Error exporting electricity bill to PDF: ' . $e->getMessage()); return AbstractController::ResultError($e->getMessage()); } } /** * Get electricity bill by ID */ public function show($id) { try { $bill = ElectricityBill::with(['creator', 'updater'])->findOrFail($id); return AbstractController::ResultSuccess($bill); } catch (\Exception $e) { Log::error('Error fetching electricity bill: ' . $e->getMessage()); return AbstractController::ResultError($e->getMessage()); } } function numberToVietnamese($number) { $units = ["", "một", "hai", "ba", "bốn", "năm", "sáu", "bảy", "tám", "chín"]; $levels = ["", "nghìn", "triệu", "tỷ"]; if ($number == 0) return "không đồng"; $number = (int)$number; $result = ""; $level = 0; while ($number > 0) { $threeDigits = $number % 1000; if ($threeDigits != 0) { $result = $this->readThreeDigits($threeDigits, $units) . " " . $levels[$level] . " " . $result; } $number = floor($number / 1000); $level++; } return ucfirst(trim(preg_replace('/\s+/', ' ', $result))) . " đồng"; } function readThreeDigits($number, $units) { $hundreds = floor($number / 100); $tens = floor(($number % 100) / 10); $ones = $number % 10; $result = ""; if ($hundreds > 0) { $result .= $units[$hundreds] . " trăm"; if ($tens == 0 && $ones > 0) { $result .= " lẻ"; } } if ($tens > 1) { $result .= " " . $units[$tens] . " mươi"; if ($ones == 1) { $result .= " mốt"; } elseif ($ones == 5) { $result .= " lăm"; } elseif ($ones > 0) { $result .= " " . $units[$ones]; } } elseif ($tens == 1) { $result .= " mười"; if ($ones == 5) { $result .= " lăm"; } elseif ($ones > 0) { $result .= " " . $units[$ones]; } } elseif ($ones > 0) { $result .= " " . $units[$ones]; } return trim($result); } }