diff --git a/app/Http/Controllers/Admin/AdminCustomerController.php b/app/Http/Controllers/Admin/AdminCustomerController.php index 4afccda..0361d3a 100644 --- a/app/Http/Controllers/Admin/AdminCustomerController.php +++ b/app/Http/Controllers/Admin/AdminCustomerController.php @@ -22,7 +22,8 @@ class AdminCustomerController extends Controller $query = User::with([ 'marks', 'orders', - 'invoices.installments' // 🔥 IMPORTANT + 'invoices.installments', + 'invoices.chargeGroups', // 🔥 for order total calculation ])->orderBy('id', 'desc'); if (!empty($search)) { @@ -159,4 +160,4 @@ class AdminCustomerController extends Controller } -} +} \ No newline at end of file diff --git a/app/Http/Controllers/Admin/AdminInvoiceController.php b/app/Http/Controllers/Admin/AdminInvoiceController.php index 2ba9d72..c4157ab 100644 --- a/app/Http/Controllers/Admin/AdminInvoiceController.php +++ b/app/Http/Controllers/Admin/AdminInvoiceController.php @@ -2,30 +2,31 @@ namespace App\Http\Controllers\Admin; -use App\Http\Controllers\Controller; +use App\Http\Controllers\Controller; // ⬅️ हे नक्की असू दे use App\Models\Invoice; use App\Models\InvoiceItem; -use App\Models\InvoiceInstallment; use App\Models\InvoiceChargeGroup; use App\Models\InvoiceChargeGroupItem; +use App\Models\InvoiceInstallment; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Mpdf\Mpdf; + class AdminInvoiceController extends Controller { // ------------------------------------------------------------- - // INVOICE LIST PAGE + // INDEX (LIST ALL INVOICES WITH FILTERS) // ------------------------------------------------------------- public function index(Request $request) { - $query = Invoice::with(['items', 'customer', 'container']); + $query = Invoice::query(); if ($request->filled('search')) { $search = $request->search; $query->where(function ($q) use ($search) { $q->where('invoice_number', 'like', "%{$search}%") - ->orWhere('customer_name', 'like', "%{$search}%"); + ->orWhere('customer_name', 'like', "%{$search}%"); }); } @@ -50,22 +51,22 @@ class AdminInvoiceController extends Controller // POPUP VIEW // ------------------------------------------------------------- public function popup($id) -{ - $invoice = Invoice::with([ - 'items', - 'chargeGroups.items', - ])->findOrFail($id); + { + $invoice = Invoice::with([ + 'items', + 'chargeGroups.items', + ])->findOrFail($id); - $shipment = null; + $shipment = null; - $groupedItemIds = $invoice->chargeGroups - ->flatMap(fn($group) => $group->items->pluck('invoice_item_id')) - ->unique() - ->values() - ->toArray(); + $groupedItemIds = $invoice->chargeGroups + ->flatMap(fn($group) => $group->items->pluck('invoice_item_id')) + ->unique() + ->values() + ->toArray(); - return view('admin.popup_invoice', compact('invoice', 'shipment', 'groupedItemIds')); -} + return view('admin.popup_invoice', compact('invoice', 'shipment', 'groupedItemIds')); + } // ------------------------------------------------------------- // EDIT INVOICE PAGE @@ -79,31 +80,29 @@ class AdminInvoiceController extends Controller 'chargeGroups.items', 'installments', ])->findOrFail($id); - - // ✅ Customer details sync — जर test data आला असेल तर fix होईल + + // ✅ Customer details sync if ($invoice->customer) { $needsUpdate = []; - + if (empty($invoice->customer_email) || $invoice->customer_email === 'test@demo.com') { $needsUpdate['customer_email'] = $invoice->customer->email; } - if (empty($invoice->customer_address) || $invoice->customer_address === 'TEST ADDRESS') { $needsUpdate['customer_address'] = $invoice->customer->address; } - if (empty($invoice->pincode) || $invoice->pincode === '999999') { $needsUpdate['pincode'] = $invoice->customer->pincode; } - + if (!empty($needsUpdate)) { $invoice->update($needsUpdate); $invoice->refresh(); } } - + $shipment = null; - + $groupedItemIds = $invoice->chargeGroups ->flatMap(function ($group) { return $group->items->pluck('invoice_item_id'); @@ -111,7 +110,7 @@ class AdminInvoiceController extends Controller ->unique() ->values() ->toArray(); - + return view('admin.invoice_edit', compact('invoice', 'shipment', 'groupedItemIds')); } @@ -122,16 +121,16 @@ class AdminInvoiceController extends Controller { Log::info('🟡 Invoice Update Request Received', [ 'invoice_id' => $id, - 'request' => $request->all(), + 'request' => $request->all(), ]); $invoice = Invoice::findOrFail($id); $data = $request->validate([ 'invoice_date' => 'required|date', - 'due_date' => 'required|date|after_or_equal:invoice_date', + 'due_date' => 'required|date|after_or_equal:invoice_date', 'status' => 'required|in:pending,paying,paid,overdue', - 'notes' => 'nullable|string', + 'notes' => 'nullable|string', ]); Log::info('✅ Validated Invoice Header Update Data', $data); @@ -140,17 +139,17 @@ class AdminInvoiceController extends Controller $invoice->refresh(); Log::info('🔍 Invoice AFTER HEADER UPDATE', [ - 'invoice_id' => $invoice->id, - 'charge_groups_total' => $invoice->charge_groups_total, - 'gst_amount' => $invoice->gst_amount, + 'invoice_id' => $invoice->id, + 'charge_groups_total' => $invoice->charge_groups_total, + 'gst_amount' => $invoice->gst_amount, 'grand_total_with_charges'=> $invoice->grand_total_with_charges, ]); $this->generateInvoicePDF($invoice); return redirect() - ->route('admin.invoices.edit', $invoice->id) - ->with('success', 'Invoice updated & PDF generated successfully.'); + ->route('admin.invoices.edit', $invoice->id) + ->with('success', 'Invoice updated & PDF generated successfully.'); } // ------------------------------------------------------------- @@ -160,12 +159,12 @@ class AdminInvoiceController extends Controller { Log::info('🟡 Invoice Items Update Request', [ 'invoice_id' => $invoice->id, - 'payload' => $request->all(), + 'payload' => $request->all(), ]); $data = $request->validate([ - 'items' => ['required', 'array'], - 'items.*.price' => ['required', 'numeric', 'min:0'], + 'items' => ['required', 'array'], + 'items.*.price' => ['required', 'numeric', 'min:0'], 'items.*.ttl_amount' => ['required', 'numeric', 'min:0'], ]); @@ -177,12 +176,12 @@ class AdminInvoiceController extends Controller if (!$item) { Log::warning('Invoice item not found or mismatched invoice', [ 'invoice_id' => $invoice->id, - 'item_id' => $itemId, + 'item_id' => $itemId, ]); continue; } - $item->price = $itemData['price']; + $item->price = $itemData['price']; $item->ttl_amount = $itemData['ttl_amount']; $item->save(); } @@ -195,15 +194,16 @@ class AdminInvoiceController extends Controller } // ------------------------------------------------------------- - // PDF GENERATION + // PDF GENERATION (EXISTING - केवळ chargeGroups load ला confirm कर) // ------------------------------------------------------------- public function generateInvoicePDF($invoice) { - $invoice->load(['items', 'customer', 'container']); + // ✅ यामध्ये chargeGroups आणि installments load कर + $invoice->load(['items', 'customer', 'container', 'chargeGroups.items', 'installments']); $shipment = null; $fileName = 'invoice-' . $invoice->invoice_number . '.pdf'; - $folder = public_path('invoices/'); + $folder = public_path('invoices/'); if (!file_exists($folder)) { mkdir($folder, 0777, true); @@ -216,13 +216,13 @@ class AdminInvoiceController extends Controller } $mpdf = new Mpdf([ - 'mode' => 'utf-8', - 'format' => 'A4', + 'mode' => 'utf-8', + 'format' => 'A4', 'default_font' => 'sans-serif', ]); $html = view('admin.pdf.invoice', [ - 'invoice' => $invoice, + 'invoice' => $invoice, 'shipment' => $shipment, ])->render(); @@ -239,9 +239,9 @@ class AdminInvoiceController extends Controller { $request->validate([ 'installment_date' => 'required|date', - 'payment_method' => 'required|string', - 'reference_no' => 'nullable|string', - 'amount' => 'required|numeric|min:1', + 'payment_method' => 'required|string', + 'reference_no' => 'nullable|string', + 'amount' => 'required|numeric|min:1', ]); $invoice = Invoice::findOrFail($invoice_id); @@ -253,51 +253,54 @@ class AdminInvoiceController extends Controller if ($request->amount > $remaining) { return response()->json([ - 'status' => 'error', + 'status' => 'error', 'message' => 'Installment amount exceeds remaining balance.', ], 422); } $installment = InvoiceInstallment::create([ - 'invoice_id' => $invoice_id, + 'invoice_id' => $invoice_id, 'installment_date' => $request->installment_date, - 'payment_method' => $request->payment_method, - 'reference_no' => $request->reference_no, - 'amount' => $request->amount, + 'payment_method' => $request->payment_method, + 'reference_no' => $request->reference_no, + 'amount' => $request->amount, ]); - $newPaid = $paidTotal + $request->amount; + $newPaid = $paidTotal + $request->amount; $remaining = max(0, $grandTotal - $newPaid); + $isOverdue = now()->startOfDay()->gt(\Carbon\Carbon::parse($invoice->due_date)->startOfDay()); + if ($grandTotal > 0 && $newPaid >= $grandTotal) { + $newStatus = 'paid'; + } elseif ($newPaid > 0 && $isOverdue) { + $newStatus = 'overdue'; + } elseif ($newPaid > 0 && !$isOverdue) { + $newStatus = 'paying'; + } elseif ($newPaid <= 0 && $isOverdue) { + $newStatus = 'overdue'; + } else { + $newStatus = 'pending'; + } - // Full payment logic (जर पूर्ण भरले तर status paid करणे, नाहीतर pending राहील) - // if ($newPaid >= $grandTotal && $grandTotal > 0) { - // $invoice->update([ - // 'payment_method' => $request->payment_method, - // 'reference_no' => $request->reference_no, - // 'status' => ($newPaid >= $grandTotal && $grandTotal > 0) ? 'paid' : $invoice->status, - // ]); - // } - - // Partial payment status logic: $invoice->update([ 'payment_method' => $request->payment_method, - 'reference_no' => $request->reference_no, - 'status' => ($newPaid >= $grandTotal && $grandTotal > 0) ? 'paid' : $invoice->status, + 'reference_no' => $request->reference_no, + 'status' => $newStatus, ]); return response()->json([ - 'status' => 'success', - 'message' => 'Installment added successfully.', - 'installment' => $installment, + 'status' => 'success', + 'message' => 'Installment added successfully.', + 'installment' => $installment, 'chargeGroupsTotal' => $invoice->charge_groups_total ?? 0, - 'gstAmount' => $invoice->gst_amount ?? 0, - 'grandTotal' => $grandTotal, - 'totalPaid' => $newPaid, - 'remaining' => $remaining, - 'isCompleted' => $remaining <= 0, - 'isZero' => $newPaid == 0, + 'gstAmount' => $invoice->gst_amount ?? 0, + 'grandTotal' => $grandTotal, + 'totalPaid' => $newPaid, + 'remaining' => $remaining, + 'newStatus' => $newStatus, + 'isCompleted' => $remaining <= 0, + 'isZero' => $newPaid == 0, ]); } @@ -307,7 +310,7 @@ class AdminInvoiceController extends Controller public function deleteInstallment($id) { $installment = InvoiceInstallment::findOrFail($id); - $invoice = $installment->invoice; + $invoice = $installment->invoice; $installment->delete(); $invoice->refresh(); @@ -317,21 +320,32 @@ class AdminInvoiceController extends Controller $paidTotal = $invoice->installments()->sum('amount'); $remaining = max(0, $grandTotal - $paidTotal); - if ($paidTotal <= 0 && $grandTotal > 0) { - $invoice->update(['status' => 'pending']); - } elseif ($paidTotal > 0 && $paidTotal < $grandTotal) { - $invoice->update(['status' => 'pending']); + $isOverdue = now()->startOfDay()->gt(\Carbon\Carbon::parse($invoice->due_date)->startOfDay()); + + if ($grandTotal > 0 && $paidTotal >= $grandTotal) { + $newStatus = 'paid'; + } elseif ($paidTotal > 0 && $isOverdue) { + $newStatus = 'overdue'; + } elseif ($paidTotal > 0 && !$isOverdue) { + $newStatus = 'paying'; + } elseif ($paidTotal <= 0 && $isOverdue) { + $newStatus = 'overdue'; + } else { + $newStatus = 'pending'; } + $invoice->update(['status' => $newStatus]); + return response()->json([ - 'status' => 'success', - 'message' => 'Installment deleted.', + 'status' => 'success', + 'message' => 'Installment deleted.', 'chargeGroupsTotal' => $invoice->charge_groups_total ?? 0, - 'gstAmount' => $invoice->gst_amount ?? 0, - 'grandTotal' => $grandTotal, - 'totalPaid' => $paidTotal, - 'remaining' => $remaining, - 'isZero' => $paidTotal == 0, + 'gstAmount' => $invoice->gst_amount ?? 0, + 'grandTotal' => $grandTotal, + 'totalPaid' => $paidTotal, + 'remaining' => $remaining, + 'newStatus' => $newStatus, + 'isZero' => $paidTotal == 0, ]); } @@ -342,126 +356,149 @@ class AdminInvoiceController extends Controller { Log::info('🟡 storeChargeGroup HIT', [ 'invoice_id' => $invoiceId, - 'payload' => $request->all(), + 'payload' => $request->all(), ]); - + $invoice = Invoice::with('items', 'chargeGroups')->findOrFail($invoiceId); - + $data = $request->validate([ - 'groupname' => 'required|string|max:255', - 'basistype' => 'required|in:ttl_qty,amount,ttl_cbm,ttl_kg', - 'basisvalue' => 'required|numeric', - 'rate' => 'required|numeric|min:0.0001', - 'autototal' => 'required|numeric|min:0.01', - 'itemids' => 'required|array', - 'itemids.*' => 'integer|exists:invoice_items,id', - - 'tax_type' => 'nullable|in:none,gst,igst', - 'gst_percent' => 'nullable|numeric|min:0|max:28', + 'groupname' => 'required|string|max:255', + 'basistype' => 'required|in:ttl_qty,amount,ttl_cbm,ttl_kg', + 'basisvalue' => 'required|numeric', + 'rate' => 'required|numeric|min:0.0001', + 'autototal' => 'required|numeric|min:0.01', + 'itemids' => 'required|array', + 'itemids.*' => 'integer|exists:invoice_items,id', + + 'tax_type' => 'nullable|in:none,gst,igst', + 'gst_percent' => 'nullable|numeric|min:0|max:28', 'total_with_gst' => 'nullable|numeric|min:0', ]); - + Log::info('✅ storeChargeGroup VALIDATED', $data); - - // duplicate name check + $exists = InvoiceChargeGroup::where('invoice_id', $invoice->id) ->where('group_name', $data['groupname']) ->exists(); - + if ($exists) { return back() ->withErrors(['groupname' => 'This group name is already used for this invoice.']) ->withInput(); } - - $taxType = $data['tax_type'] ?? 'gst'; + + $taxType = $data['tax_type'] ?? 'gst'; $gstPercent = $data['gst_percent'] ?? 0; - $baseTotal = $data['autototal']; - + $baseTotal = $data['autototal']; + $totalWithGst = $data['total_with_gst'] ?? $baseTotal; if ($totalWithGst == 0 && $gstPercent > 0) { - $gstAmount = ($baseTotal * $gstPercent) / 100; + $gstAmount = ($baseTotal * $gstPercent) / 100; $totalWithGst = $baseTotal + $gstAmount; } - - // 1) Group create + $group = InvoiceChargeGroup::create([ - 'invoice_id' => $invoice->id, - 'group_name' => $data['groupname'], - 'basis_type' => $data['basistype'], - 'basis_value' => $data['basisvalue'], - 'rate' => $data['rate'], - 'total_charge' => $baseTotal, - 'tax_type' => $taxType, - 'gst_percent' => $gstPercent, + 'invoice_id' => $invoice->id, + 'group_name' => $data['groupname'], + 'basis_type' => $data['basistype'], + 'basis_value' => $data['basisvalue'], + 'rate' => $data['rate'], + 'total_charge' => $baseTotal, + 'tax_type' => $taxType, + 'gst_percent' => $gstPercent, 'total_with_gst' => $totalWithGst, ]); - - // 2) Items link + foreach ($data['itemids'] as $itemId) { InvoiceChargeGroupItem::create([ - 'group_id' => $group->id, + 'group_id' => $group->id, 'invoice_item_id' => $itemId, ]); } - - // 3) सर्व groups वरून invoice level totals + $invoice->load('chargeGroups'); - - $chargeGroupsBase = $invoice->chargeGroups->sum('total_charge'); // base - $chargeGroupsWithG = $invoice->chargeGroups->sum('total_with_gst'); // base + gst - $chargeGroupsGst = $chargeGroupsWithG - $chargeGroupsBase; // gst only - + + $chargeGroupsBase = $invoice->chargeGroups->sum('total_charge'); + $chargeGroupsWithG = $invoice->chargeGroups->sum('total_with_gst'); + $chargeGroupsGst = $chargeGroupsWithG - $chargeGroupsBase; + $invoiceGstPercent = $group->gst_percent ?? 0; - $invoiceTaxType = $group->tax_type ?? 'gst'; - + $invoiceTaxType = $group->tax_type ?? 'gst'; + $cgstPercent = 0; $sgstPercent = 0; $igstPercent = 0; - + if ($invoiceTaxType === 'gst') { $cgstPercent = $invoiceGstPercent / 2; $sgstPercent = $invoiceGstPercent / 2; } elseif ($invoiceTaxType === 'igst') { $igstPercent = $invoiceGstPercent; } - - // 🔴 इथे main fix: - // final_amount = base (total_charge sum) - // final_amount_with_gst = base + gst (total_with_gst sum) - // grand_total_with_charges = final_amount_with_gst (same) + $invoice->update([ - 'charge_groups_total' => $chargeGroupsBase, - 'gst_amount' => $chargeGroupsGst, - 'gst_percent' => $invoiceGstPercent, - 'tax_type' => $invoiceTaxType, - 'cgst_percent' => $cgstPercent, - 'sgst_percent' => $sgstPercent, - 'igst_percent' => $igstPercent, - - 'final_amount' => $chargeGroupsBase, - 'final_amount_with_gst' => $chargeGroupsWithG, + 'charge_groups_total' => $chargeGroupsBase, + 'gst_amount' => $chargeGroupsGst, + 'gst_percent' => $invoiceGstPercent, + 'tax_type' => $invoiceTaxType, + 'cgst_percent' => $cgstPercent, + 'sgst_percent' => $sgstPercent, + 'igst_percent' => $igstPercent, + + 'final_amount' => $chargeGroupsBase, + 'final_amount_with_gst' => $chargeGroupsWithG, 'grand_total_with_charges' => $chargeGroupsWithG, ]); - + Log::info('✅ Invoice updated from Charge Group (CG total + GST)', [ - 'invoice_id' => $invoice->id, - 'charge_groups_total' => $chargeGroupsBase, - 'gst_amount' => $chargeGroupsGst, - 'gst_percent' => $invoiceGstPercent, - 'tax_type' => $invoiceTaxType, - 'cgst_percent' => $cgstPercent, - 'sgst_percent' => $sgstPercent, - 'igst_percent' => $igstPercent, - 'final_amount' => $invoice->final_amount, - 'final_amount_with_gst' => $invoice->final_amount_with_gst, + 'invoice_id' => $invoice->id, + 'charge_groups_total' => $chargeGroupsBase, + 'gst_amount' => $chargeGroupsGst, 'grand_total_with_charges'=> $invoice->grand_total_with_charges, ]); - - return response()->json([ + + return response()->json([ 'success' => true, 'message' => 'Charge group saved successfully.', 'group_id' => $group->id, ]); } -} \ No newline at end of file + + // ============================================ + // 🆕 PDF DOWNLOAD (Direct browser download) + // ============================================ + public function downloadPdf($id) + { + $invoice = Invoice::with(['items', 'customer', 'container', 'chargeGroups.items', 'installments']) + ->findOrFail($id); + + $fileName = 'invoice-' . $invoice->invoice_number . '.pdf'; + $folder = public_path('invoices/'); + $filePath = $folder . $fileName; + + // जर PDF exist नसेल तर generate कर + if (!file_exists($filePath)) { + $this->generateInvoicePDF($invoice); + } + + return response()->download($filePath, $fileName); + } + + // ============================================ + // 🆕 EXCEL DOWNLOAD (CSV format - simple) + // ============================================ + + + public function share($id) +{ + $invoice = Invoice::findOrFail($id); + + // इथे तुला जसं share करायचंय तसं logic टाक: + // उदा. public link generate करून redirect कर, किंवा WhatsApp deeplink, इ. + + $url = route('admin.invoices.popup', $invoice->id); // example: popup link share + + return redirect()->away('https://wa.me/?text=' . urlencode($url)); +} + +} diff --git a/app/Http/Controllers/Admin/AdminReportController.php b/app/Http/Controllers/Admin/AdminReportController.php index 60f0dab..8b5d20b 100644 --- a/app/Http/Controllers/Admin/AdminReportController.php +++ b/app/Http/Controllers/Admin/AdminReportController.php @@ -5,104 +5,197 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; +use Maatwebsite\Excel\Facades\Excel; +use Mpdf\Mpdf; class AdminReportController extends Controller { - /** - * Display the reports page with joined data - */ - // public function index(Request $request) - // { - /********************************************************* - * OLD FLOW (Order + Shipment + Invoice) - * फक्त reference साठी ठेवलेला, वापरत नाही. - *********************************************************/ - - /* - $reports = DB::table('orders') - ->join('shipment_items', 'shipment_items.order_id', '=', 'orders.id') - ->join('shipments', 'shipments.id', '=', 'shipment_items.shipment_id') - ->join('invoices', 'invoices.order_id', '=', 'orders.id') - ->leftJoin('mark_list', 'mark_list.mark_no', '=', 'orders.mark_no') - ->leftJoin('users', 'users.customer_id', '=', 'mark_list.customer_id') - ->select(...) - ->orderBy('shipments.shipment_date', 'desc') - ->get(); - */ - - /********************************************************* - * NEW FLOW (Container + Invoice + MarkList) - *********************************************************/ - - // $reports = DB::table('invoices') - // ->join('containers', 'containers.id', '=', 'invoices.containerid') - // ->leftJoin('mark_list', 'mark_list.markno', '=', 'invoices.markno') - // ->select( - // 'invoices.id as invoicepk', - // 'invoices.invoicenumber', - // 'invoices.invoicedate', - // 'invoices.finalamount', - // 'invoices.finalamountwithgst', - // 'invoices.gstpercent', - // 'invoices.gstamount', - // 'invoices.status as invoicestatus', - // 'invoices.markno', - - // 'containers.id as containerpk', - // 'containers.containernumber', - // 'containers.containerdate', - // 'containers.containername', - - // 'mark_list.companyname', - // 'mark_list.customername' - // ) - // ->orderBy('containers.containerdate', 'desc') - // ->get(); - - // return view('admin.reports', compact('reports')); - // } - - - - public function index(Request $request) + // UI साठी main action + public function containerReport(Request $request) { - $reports = DB::table('invoices') + $reports = $this->buildContainerReportQuery($request)->get(); + + return view('admin.reports', compact('reports')); + } + + // ही common query — filters accept करते + protected function buildContainerReportQuery(Request $request = null) + { + $query = DB::table('invoices') ->join('containers', 'containers.id', '=', 'invoices.container_id') - ->leftJoin('mark_list', 'mark_list.mark_no', '=', 'invoices.mark_no') + ->leftJoinSub( + DB::table('invoice_installments') + ->select('invoice_id', DB::raw('COALESCE(SUM(amount), 0) as total_paid')) + ->groupBy('invoice_id'), + 'inst', + 'inst.invoice_id', + '=', + 'invoices.id' + ) ->select( - // INVOICE - 'invoices.id as invoicepk', - 'invoices.invoice_number', - 'invoices.invoice_date', - 'invoices.final_amount', - 'invoices.final_amount_with_gst', - 'invoices.gst_percent', - 'invoices.gst_amount', - 'invoices.status as invoicestatus', - 'invoices.mark_no', - - // CONTAINER - 'containers.id as containerpk', + 'containers.id as container_id', 'containers.container_number', 'containers.container_date', 'containers.container_name', - - // RAW FIELDS (for reference/debug if needed) - 'invoices.company_name as inv_company_name', - 'invoices.customer_name as inv_customer_name', - 'mark_list.company_name as ml_company_name', - 'mark_list.customer_name as ml_customer_name', - - // FINAL FIELDS (automatically pick invoice first, else mark_list) - DB::raw('COALESCE(invoices.company_name, mark_list.company_name) as company_name'), - DB::raw('COALESCE(invoices.customer_name, mark_list.customer_name) as customer_name') - ) - ->orderBy('invoices.invoice_date', 'desc') - ->orderBy('invoices.id', 'desc') - ->get(); - - return view('admin.reports', compact('reports')); + DB::raw('COUNT(DISTINCT invoices.mark_no) as total_mark_nos'), + DB::raw('COUNT(DISTINCT invoices.customer_id) as total_customers'), + DB::raw('COUNT(invoices.id) as total_invoices'), + + DB::raw('COALESCE(SUM(invoices.charge_groups_total), 0) as total_invoice_amount'), + DB::raw('COALESCE(SUM(invoices.gst_amount), 0) as total_gst_amount'), + DB::raw('COALESCE(SUM(invoices.grand_total_with_charges), 0) as total_payable'), + DB::raw('COALESCE(SUM(inst.total_paid), 0) as total_paid'), + DB::raw('GREATEST(0, COALESCE(SUM(invoices.grand_total_with_charges), 0) - COALESCE(SUM(inst.total_paid), 0)) as total_remaining'), + + DB::raw(" + CASE + WHEN COUNT(invoices.id) > 0 + AND SUM(CASE WHEN invoices.status != 'paid' THEN 1 ELSE 0 END) = 0 + THEN 'paid' + WHEN SUM(CASE WHEN invoices.status = 'overdue' THEN 1 ELSE 0 END) > 0 + THEN 'overdue' + WHEN SUM(CASE WHEN invoices.status = 'paying' THEN 1 ELSE 0 END) > 0 + THEN 'paying' + ELSE 'pending' + END as container_status + ") + ) + ->groupBy( + 'containers.id', + 'containers.container_number', + 'containers.container_date', + 'containers.container_name' + ) + ->orderBy('containers.container_date', 'desc') + ->orderBy('containers.id', 'desc'); + + // ── Filters ────────────────────────────────────────────────────── + if ($request) { + if ($request->filled('from_date')) { + $query->whereDate('containers.container_date', '>=', $request->from_date); + } + + if ($request->filled('to_date')) { + $query->whereDate('containers.container_date', '<=', $request->to_date); + } + + if ($request->filled('status')) { + // container_status हे aggregate expression आहे, + // त्यामुळे HAVING clause वापरतो + $query->havingRaw(" + CASE + WHEN COUNT(invoices.id) > 0 + AND SUM(CASE WHEN invoices.status != 'paid' THEN 1 ELSE 0 END) = 0 + THEN 'paid' + WHEN SUM(CASE WHEN invoices.status = 'overdue' THEN 1 ELSE 0 END) > 0 + THEN 'overdue' + WHEN SUM(CASE WHEN invoices.status = 'paying' THEN 1 ELSE 0 END) > 0 + THEN 'paying' + ELSE 'pending' + END = ? + ", [$request->status]); + } + } + + return $query; } - -} + + // ---- Excel export ---- + public function containerReportExcel(Request $request) + { + $reports = $this->buildContainerReportQuery($request)->get(); + + $headings = [ + 'Container No', + 'Container Date', + 'Total Mark Nos', + 'Total Customers', + 'Total Invoices', + 'Invoice Amount (Before GST)', + 'GST Amount', + 'Payable Amount (Incl. GST)', + 'Paid Amount', + 'Remaining Amount', + 'Container Status', + ]; + + $rows = $reports->map(function ($r) { + return [ + $r->container_number, + $r->container_date, + $r->total_mark_nos, + $r->total_customers, + $r->total_invoices, + $r->total_invoice_amount, + $r->total_gst_amount, + $r->total_payable, + $r->total_paid, + $r->total_remaining, + $r->container_status, + ]; + })->toArray(); + + $export = new class($headings, $rows) implements + \Maatwebsite\Excel\Concerns\FromArray, + \Maatwebsite\Excel\Concerns\WithHeadings + { + private $headings; + private $rows; + + public function __construct($headings, $rows) + { + $this->headings = $headings; + $this->rows = $rows; + } + + public function array(): array + { + return $this->rows; + } + + public function headings(): array + { + return $this->headings; + } + }; + + return Excel::download( + $export, + 'container-report-' . now()->format('Ymd-His') . '.xlsx' + ); + } + + // ---- PDF export ---- + public function containerReportPdf(Request $request) + { + $reports = $this->buildContainerReportQuery($request)->get(); + + $html = view('admin.reports', [ + 'reports' => $reports, + 'isPdf' => true, + ])->render(); + + $mpdf = new \Mpdf\Mpdf([ + 'mode' => 'utf-8', + 'format' => 'A4-L', + 'default_font' => 'dejavusans', + 'margin_top' => 8, + 'margin_right' => 8, + 'margin_bottom' => 10, + 'margin_left' => 8, + ]); + + $mpdf->SetHTMLHeader(''); + $mpdf->SetHTMLFooter(''); + + $mpdf->WriteHTML($html); + + $fileName = 'container-report-' . now()->format('Ymd-His') . '.pdf'; + + return response($mpdf->Output($fileName, 'S'), 200, [ + 'Content-Type' => 'application/pdf', + 'Content-Disposition' => 'attachment; filename="' . $fileName . '"', + ]); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/ContainerController.php b/app/Http/Controllers/ContainerController.php index 94ac571..6312d9e 100644 --- a/app/Http/Controllers/ContainerController.php +++ b/app/Http/Controllers/ContainerController.php @@ -565,8 +565,6 @@ class ContainerController extends Controller $invoice->save(); $invoiceCount++; - $totalAmount = 0; - foreach ($rowsForCustomer as $item) { $row = $item['row']; $offset = $item['offset']; @@ -606,16 +604,7 @@ class ContainerController extends Controller 'shop_no' => $shopNo, 'mark_no' => $mark, // ✅ save mark_no from Excel ]); - - $totalAmount += $ttlAmount; } - - $invoice->final_amount = $totalAmount; - $invoice->gst_percent = 0; - $invoice->gst_amount = 0; - $invoice->final_amount_with_gst = $totalAmount; - - $invoice->save(); } $msg = "Container '{$container->container_number}' created with {$savedCount} rows and {$invoiceCount} customer invoice(s)."; @@ -972,4 +961,4 @@ class ContainerController extends Controller 'summary' => $summary, ]); } -} +} \ No newline at end of file diff --git a/public/invoices/invoice-INV-2026-000253.pdf b/public/invoices/invoice-INV-2026-000253.pdf new file mode 100644 index 0000000..b65fd3d Binary files /dev/null and b/public/invoices/invoice-INV-2026-000253.pdf differ diff --git a/public/invoices/invoice-INV-2026-000256.pdf b/public/invoices/invoice-INV-2026-000256.pdf new file mode 100644 index 0000000..4c9817b Binary files /dev/null and b/public/invoices/invoice-INV-2026-000256.pdf differ diff --git a/public/invoices/invoice-INV-2026-000257.pdf b/public/invoices/invoice-INV-2026-000257.pdf new file mode 100644 index 0000000..55d2fc7 Binary files /dev/null and b/public/invoices/invoice-INV-2026-000257.pdf differ diff --git a/public/invoices/invoice-INV-2026-000258.pdf b/public/invoices/invoice-INV-2026-000258.pdf new file mode 100644 index 0000000..13b677c Binary files /dev/null and b/public/invoices/invoice-INV-2026-000258.pdf differ diff --git a/public/invoices/invoice-INV-2026-000259.pdf b/public/invoices/invoice-INV-2026-000259.pdf new file mode 100644 index 0000000..b3211bf Binary files /dev/null and b/public/invoices/invoice-INV-2026-000259.pdf differ diff --git a/public/invoices/invoice-INV-2026-000260.pdf b/public/invoices/invoice-INV-2026-000260.pdf new file mode 100644 index 0000000..c39f12a Binary files /dev/null and b/public/invoices/invoice-INV-2026-000260.pdf differ diff --git a/public/invoices/invoice-INV-2026-000261.pdf b/public/invoices/invoice-INV-2026-000261.pdf new file mode 100644 index 0000000..c1e8e6d Binary files /dev/null and b/public/invoices/invoice-INV-2026-000261.pdf differ diff --git a/public/invoices/invoice-INV-2026-000262.pdf b/public/invoices/invoice-INV-2026-000262.pdf new file mode 100644 index 0000000..ae54fd0 Binary files /dev/null and b/public/invoices/invoice-INV-2026-000262.pdf differ diff --git a/public/invoices/invoice-INV-2026-000263.pdf b/public/invoices/invoice-INV-2026-000263.pdf new file mode 100644 index 0000000..7c7bc56 Binary files /dev/null and b/public/invoices/invoice-INV-2026-000263.pdf differ diff --git a/public/invoices/invoice-INV-2026-000264.pdf b/public/invoices/invoice-INV-2026-000264.pdf new file mode 100644 index 0000000..3eb940e Binary files /dev/null and b/public/invoices/invoice-INV-2026-000264.pdf differ diff --git a/public/invoices/invoice-INV-2026-000265.pdf b/public/invoices/invoice-INV-2026-000265.pdf new file mode 100644 index 0000000..a8eddfa Binary files /dev/null and b/public/invoices/invoice-INV-2026-000265.pdf differ diff --git a/resources/views/admin/container_show.blade.php b/resources/views/admin/container_show.blade.php index 2e7b39b..520ed3b 100644 --- a/resources/views/admin/container_show.blade.php +++ b/resources/views/admin/container_show.blade.php @@ -40,7 +40,6 @@ margin-top: 2px; } - /* DOWNLOAD BUTTONS - NEW STYLES */ .cm-download-pdf { background: linear-gradient(100deg, #4c6fff 0%, #8e54e9 100%) !important; color: #fff !important; @@ -287,7 +286,7 @@ } .cm-table-scroll-outer { - margin: 10px 14px 0 14px; + margin: 10px 14px 30px 14px; border-radius: 14px; border: 1.5px solid #c9a359; box-shadow: 0 4px 14px rgba(76,111,255,0.18); @@ -487,11 +486,6 @@ grid-template-columns: 1fr; } } - - .cm-table-scroll-outer { - margin: 10px 14px 30px 14px; /* फक्त हे बदल करा */ -} -
@@ -522,7 +516,6 @@
-
Container Information
@@ -682,7 +675,7 @@
- Total rows: {{ $container->rows->count() }}   Edit cells then click "Save Changes". + Total rows: {{ $container->rows->count() }} Edit cells then click "Save Changes". @@ -745,9 +738,9 @@ str_contains($norm, 'TOTALAMOUNT') ); - $isTotalColumn = $isTotalQty || $isTotalCbm || $isTotalKg || $isAmount; + $isTotalColumn = $isTotalQty || $isTotalCbm || $isTotalKg || $isAmount; $isLockedByInvoice = in_array($row->row_index, $lockedRowIndexes ?? []); - $isReadOnly = $isTotalColumn || $container->status !== 'pending' || $isLockedByInvoice; + $isReadOnly = $isTotalColumn || $container->status !== 'pending' || $isLockedByInvoice; @endphp @@ -792,7 +785,6 @@ @endif -
-@endsection +@endsection \ No newline at end of file diff --git a/resources/views/admin/invoice.blade.php b/resources/views/admin/invoice.blade.php index f8ffd6e..2cc6c2a 100644 --- a/resources/views/admin/invoice.blade.php +++ b/resources/views/admin/invoice.blade.php @@ -1236,7 +1236,7 @@ Customer Container {{-- NEW --}} Final Amount - GST % + GST Amount Total w/GST Status Invoice Date @@ -1286,8 +1286,8 @@ ₹{{ number_format($invoice->final_amount, 2) }} - - {{ $invoice->gst_percent }}% + + ₹{{ number_format($invoice->gst_amount, 2) }} @@ -1379,8 +1379,8 @@ ₹{{ number_format($invoice->final_amount, 2) }}
- GST - {{ $invoice->gst_percent }}% + GST Amount + ₹{{ number_format($invoice->gst_amount, 2) }}
Total @@ -1694,7 +1694,7 @@ document.addEventListener('DOMContentLoaded', function() { ${invoice.container ? (invoice.container.container_number ?? '—') : '—'} ₹${parseFloat(invoice.final_amount).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2})} - ${invoice.gst_percent}% + ₹${parseFloat(invoice.gst_amount).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2})} ₹${parseFloat(invoice.final_amount_with_gst).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2})} @@ -1756,8 +1756,8 @@ document.addEventListener('DOMContentLoaded', function() { ₹${parseFloat(invoice.final_amount).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2})}
- GST - ${invoice.gst_percent}% + GST Amount + ₹${parseFloat(invoice.gst_amount).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2})}
Total diff --git a/resources/views/admin/invoice_edit.blade.php b/resources/views/admin/invoice_edit.blade.php index 0f651f1..39e47de 100644 --- a/resources/views/admin/invoice_edit.blade.php +++ b/resources/views/admin/invoice_edit.blade.php @@ -325,95 +325,15 @@
- {{-- Edit Invoice Header --}} -
-
-

- - Edit Invoice Details -

- -
-
-
- @csrf - -
- {{-- Invoice Date --}} -
- - -
- - {{-- Due Date --}} -
- - -
- - {{-- Final Amount (With GST) – Charge Groups Total --}} -
- - -
- - {{-- Status --}} -
- - -
- - {{-- Notes --}} -
- - -
-
- -
- -
-
-
-
+ @if(false) + {{-- Edit Invoice Details card – HIDDEN --}} + {{-- तुझा full header edit form इथे hidden ठेवलेला आहे --}} + @endif @php $totalPaid = $invoice->totalPaid(); $remaining = $invoice->remainingAmount(); - // Mixed tax type label from charge groups $taxTypes = $invoice->chargeGroups ? $invoice->chargeGroups->pluck('tax_type')->filter()->unique()->values() : collect([]); @@ -440,47 +360,10 @@ } @endphp - {{-- Amount Breakdown --}} -
-
- Amount Breakdown -
- -
- Tax Type - - {{ $taxTypeLabel }} - -
- -
- GST Amount - - ₹{{ number_format($invoice->gst_amount, 2) }} - -
- -
- Grand Total (Charges + GST) - - ₹{{ number_format($invoice->grand_total_with_charges, 2) }} - -
- -
- Total Paid - - ₹{{ number_format($totalPaid, 2) }} - -
- -
- Remaining - - ₹{{ number_format(max(0, $remaining), 2) }} - -
-
+ @if(false) + {{-- Amount Breakdown HIDDEN --}} + {{-- जुनं breakdown section इथे hidden आहे --}} + @endif {{-- Summary cards --}}
@@ -491,13 +374,13 @@
Grand Total (Charges + GST)