diff --git a/app/Http/Controllers/Admin/AdminInvoiceController.php b/app/Http/Controllers/Admin/AdminInvoiceController.php index ef0820d..b813ae3 100644 --- a/app/Http/Controllers/Admin/AdminInvoiceController.php +++ b/app/Http/Controllers/Admin/AdminInvoiceController.php @@ -8,6 +8,7 @@ use App\Models\InvoiceItem; use App\Models\InvoiceInstallment; use App\Models\InvoiceChargeGroup; use App\Models\InvoiceChargeGroupItem; +use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; @@ -20,9 +21,9 @@ class AdminInvoiceController extends Controller // ------------------------------------------------------------- public function index(Request $request) { + // Container relation सह invoices load करतो $query = Invoice::with(['items', 'customer', 'container']); - - // Search + if ($request->filled('search')) { $search = $request->search; $query->where(function ($q) use ($search) { @@ -30,42 +31,51 @@ class AdminInvoiceController extends Controller ->orWhere('customer_name', 'like', "%{$search}%"); }); } - - // Status filter + if ($request->filled('status') && $request->status !== 'all') { $query->where('status', $request->status); } - - // Date range filter (invoice_date वर) + if ($request->filled('start_date')) { $query->whereDate('invoice_date', '>=', $request->start_date); } - + if ($request->filled('end_date')) { $query->whereDate('invoice_date', '<=', $request->end_date); } - - // Latest first + $invoices = $query->latest()->get(); - + return view('admin.invoice', compact('invoices')); - } + } // ------------------------------------------------------------- - // POPUP VIEW (AJAX) + // POPUP VIEW + CUSTOMER DATA SYNC // ------------------------------------------------------------- public function popup($id) { $invoice = Invoice::with([ 'items', - 'customer', - 'container', - 'chargeGroups.items.item', + 'chargeGroups.items', ])->findOrFail($id); + // demo update असेल तर ठेव/काढ + $invoice->update([ + 'customer_email' => 'test@demo.com', + 'customer_address' => 'TEST ADDRESS', + 'pincode' => '999999', + ]); + $shipment = null; - return view('admin.popup_invoice', compact('invoice', 'shipment')); + // आधीच group मध्ये असलेले item ids + $groupedItemIds = $invoice->chargeGroups + ->flatMap(fn($group) => $group->items->pluck('invoice_item_id')) + ->unique() + ->values() + ->toArray(); + + return view('admin.popup_invoice', compact('invoice', 'shipment', 'groupedItemIds')); } // ------------------------------------------------------------- @@ -134,10 +144,10 @@ class AdminInvoiceController extends Controller $data['igst_percent'] = $taxPercent; } - $gstAmount = ($finalAmount * $taxPercent) / 100; - $data['gst_amount'] = $gstAmount; + $gstAmount = ($finalAmount * $taxPercent) / 100; + $data['gst_amount'] = $gstAmount; $data['final_amount_with_gst'] = $finalAmount + $gstAmount; - $data['gst_percent'] = $taxPercent; + $data['gst_percent'] = $taxPercent; Log::info('📌 Final Calculated Invoice Values', [ 'invoice_id' => $invoice->id, @@ -177,7 +187,7 @@ class AdminInvoiceController extends Controller } // ------------------------------------------------------------- - // 🔹 UPDATE INVOICE ITEMS (price + ttl_amount) + // UPDATE INVOICE ITEMS // ------------------------------------------------------------- public function updateItems(Request $request, Invoice $invoice) { @@ -230,10 +240,16 @@ class AdminInvoiceController extends Controller $gstAmount = $newBaseAmount * $gstPercent / 100; $finalWithGst = $newBaseAmount + $gstAmount; - $invoice->final_amount = $newBaseAmount; - $invoice->gst_amount = $gstAmount; - $invoice->final_amount_with_gst = $finalWithGst; - $invoice->gst_percent = $gstPercent; + $invoice->final_amount = $newBaseAmount; + $invoice->gst_amount = $gstAmount; + $invoice->final_amount_with_gst = $finalWithGst; + $invoice->gst_percent = $gstPercent; + $invoice->save(); + + // ⭐ Total Charges (groups समावेत) पुन्हा कॅलक्युलेट + $chargeGroupsTotal = $invoice->chargeGroups()->sum('total_charge'); + $invoice->charge_groups_total = $chargeGroupsTotal; + $invoice->grand_total_with_charges = $invoice->final_amount_with_gst + $chargeGroupsTotal; $invoice->save(); Log::info('✅ Invoice items updated & totals recalculated', [ @@ -245,13 +261,15 @@ class AdminInvoiceController extends Controller 'cgst_percent' => $invoice->cgst_percent, 'sgst_percent' => $invoice->sgst_percent, 'igst_percent' => $invoice->igst_percent, + 'charge_groups_total' => $invoice->charge_groups_total, + 'grand_total_with_charges' => $invoice->grand_total_with_charges, ]); return back()->with('success', 'Invoice items updated successfully.'); } // ------------------------------------------------------------- - // PDF GENERATION USING mPDF + // PDF GENERATION // ------------------------------------------------------------- public function generateInvoicePDF($invoice) { @@ -302,7 +320,10 @@ class AdminInvoiceController extends Controller $invoice = Invoice::findOrFail($invoice_id); $paidTotal = $invoice->installments()->sum('amount'); - $remaining = $invoice->final_amount_with_gst - $paidTotal; + + // 👇 Total Charges (grand_total_with_charges) वरून remaining + $grandTotal = $invoice->grand_total_with_charges; + $remaining = $grandTotal - $paidTotal; if ($request->amount > $remaining) { return response()->json([ @@ -331,11 +352,12 @@ class AdminInvoiceController extends Controller 'installment' => $installment, 'totalPaid' => $newPaid, 'gstAmount' => $invoice->gst_amount, - 'finalAmountWithGst' => $invoice->final_amount_with_gst, + 'finalAmountWithGst' => $grandTotal, // इथे grand total पाठव 'baseAmount' => $invoice->final_amount, - 'remaining' => max(0, $invoice->final_amount_with_gst - $newPaid), - 'isCompleted' => $newPaid >= $invoice->final_amount_with_gst, + 'remaining' => max(0, $grandTotal - $newPaid), + 'isCompleted' => $newPaid >= $grandTotal, ]); + } // ------------------------------------------------------------- @@ -348,34 +370,32 @@ class AdminInvoiceController extends Controller $installment->delete(); - $paidTotal = $invoice->installments()->sum('amount'); - $remaining = $invoice->final_amount_with_gst - $paidTotal; - - if ($remaining > 0 && $invoice->status === 'paid') { - $invoice->update(['status' => 'pending']); - } - + $paidTotal = $invoice->installments()->sum('amount'); + $grandTotal = $invoice->grand_total_with_charges; + $remaining = $grandTotal - $paidTotal; + return response()->json([ 'status' => 'success', 'message' => 'Installment deleted.', 'totalPaid' => $paidTotal, 'gstAmount' => $invoice->gst_amount, - 'finalAmountWithGst' => $invoice->final_amount_with_gst, + 'finalAmountWithGst' => $grandTotal, // इथेही 'baseAmount' => $invoice->final_amount, 'remaining' => $remaining, 'isZero' => $paidTotal == 0, ]); + } // ------------------------------------------------------------- - // CHARGE GROUP SAVE (NEW) + // CHARGE GROUP SAVE (no AJAX branch) // ------------------------------------------------------------- public function storeChargeGroup(Request $request, $invoiceId) { $invoice = Invoice::with('items')->findOrFail($invoiceId); - + $data = $request->validate([ - 'group_name' => 'nullable|string|max:255', + 'group_name' => 'required|string|max:255', 'basis_type' => 'required|in:ttl_qty,amount,ttl_cbm,ttl_kg', 'basis_value' => 'required|numeric', 'rate' => 'required|numeric|min:0.0001', @@ -383,62 +403,47 @@ class AdminInvoiceController extends Controller 'item_ids' => 'required|array', 'item_ids.*' => 'integer|exists:invoice_items,id', ]); - + + $exists = InvoiceChargeGroup::where('invoice_id', $invoice->id) + ->where('group_name', $data['group_name']) + ->exists(); + + if ($exists) { + return back() + ->withErrors(['group_name' => 'This group name is already used for this invoice.']) + ->withInput(); + } + $group = InvoiceChargeGroup::create([ 'invoice_id' => $invoice->id, - 'group_name' => $data['group_name'] ?? null, + 'group_name' => $data['group_name'], 'basis_type' => $data['basis_type'], 'basis_value' => $data['basis_value'], 'rate' => $data['rate'], 'total_charge' => $data['auto_total'], ]); - + foreach ($data['item_ids'] as $itemId) { InvoiceChargeGroupItem::create([ 'group_id' => $group->id, 'invoice_item_id' => $itemId, ]); } - - if ($request->ajax()) { - // load items with invoice item relation - $group->load(['items.item']); - - // prepare simple array for JS - $itemsPayload = $group->items->map(function ($gi) { - $it = $gi->item; - return [ - 'description' => $it->description, - 'qty' => $it->qty, - 'ttlqty' => $it->ttl_qty, - 'cbm' => $it->cbm, - 'ttlcbm' => $it->ttl_cbm, - 'kg' => $it->kg, - 'ttlkg' => $it->ttl_kg, - 'amount' => $it->ttl_amount, - ]; - }); - - return response()->json([ - 'success' => true, - 'message' => 'Charge group created successfully.', - 'group' => [ - 'id' => $group->id, - 'group_name' => $group->group_name, - 'basis_type' => $group->basis_type, - 'basis_value' => $group->basis_value, - 'rate' => $group->rate, - 'total_charge'=> $group->total_charge, - 'items' => $itemsPayload, - ], - ]); - } - + + // ⭐ Charge groups नुसार Total Charges सेट करा + $chargeGroupsTotal = $invoice->chargeGroups()->sum('total_charge'); + $grandTotal = $invoice->final_amount_with_gst + $chargeGroupsTotal; + + $invoice->update([ + 'charge_groups_total' => $chargeGroupsTotal, + 'grand_total_with_charges' => $grandTotal, + ]); + return redirect() ->back() ->with('success', 'Charge group saved successfully.'); } - + public function download(Invoice $invoice) { if (!$invoice->pdf_path || !Storage::exists($invoice->pdf_path)) { diff --git a/app/Http/Controllers/Admin/AdminOrderController.php b/app/Http/Controllers/Admin/AdminOrderController.php index 9bfaa3d..91acdf2 100644 --- a/app/Http/Controllers/Admin/AdminOrderController.php +++ b/app/Http/Controllers/Admin/AdminOrderController.php @@ -70,11 +70,13 @@ class AdminOrderController extends Controller 'invoices.final_amount_with_gst', 'invoices.status as invoice_status', 'invoices.mark_no', + 'invoices.container_id', // <<< हे नक्की घाल 'containers.container_number', 'containers.container_date', 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') ) + ->when($request->filled('search'), function ($q) use ($request) { $search = trim($request->search); $q->where(function ($qq) use ($search) { diff --git a/app/Http/Controllers/ContainerController.php b/app/Http/Controllers/ContainerController.php index aeb04d0..e1c570e 100644 --- a/app/Http/Controllers/ContainerController.php +++ b/app/Http/Controllers/ContainerController.php @@ -10,6 +10,8 @@ use App\Models\InvoiceItem; use Illuminate\Http\Request; use Maatwebsite\Excel\Facades\Excel; use Carbon\Carbon; +use Barryvdh\DomPDF\Facade\Pdf; +use Illuminate\Support\Facades\Storage; // <-- added for Excel download class ContainerController extends Controller { @@ -241,8 +243,8 @@ class ContainerController extends Controller } // ROWS CLEANING - $dataRows = array_slice($rows, $headerRowIndex + 1); - $cleanedRows = []; + $dataRows = array_slice($rows, $headerRowIndex + 1); + $cleanedRows = []; $unmatchedRowsData = []; foreach ($dataRows as $offset => $row) { @@ -253,7 +255,7 @@ class ContainerController extends Controller $rowText = strtoupper(implode(' ', $trimmedRow)); if ( stripos($rowText, 'TOTAL') !== false || - stripos($rowText, 'TTL') !== false || + stripos($rowText, 'TTL') !== false || stripos($rowText, 'GRAND') !== false ) { continue; @@ -280,10 +282,7 @@ class ContainerController extends Controller ->withInput(); } - /* - * FORMULA CHECK – UPDATED WITH AMOUNT FIX + NUMBER SANITIZER - */ - + // FORMULA CHECK $cleanNumber = function ($value) { if (is_string($value)) { $value = str_replace(',', '', trim($value)); @@ -311,7 +310,6 @@ class ContainerController extends Controller $desc = $essentialColumns['desc_col'] !== null ? (string)($row[$essentialColumns['desc_col']] ?? '') : ''; $mark = $essentialColumns['itemno_col'] !== null ? (string)($row[$essentialColumns['itemno_col']] ?? '') : ''; - // expected $expTtlQty = $qty * $ctn; $expTtlCbm = $cbm * $ctn; $expTtlKg = $kg * $ctn; @@ -350,7 +348,6 @@ class ContainerController extends Controller } if (!empty($rowErrors)) { - // full row data map for excel table $rowData = []; foreach ($header as $colIndex => $headingText) { $value = $row[$colIndex] ?? null; @@ -368,7 +365,7 @@ class ContainerController extends Controller } } - // MARK CHECK: strict - collect ALL marks + unmatched rows + // MARK CHECK $marksFromExcel = []; foreach ($cleanedRows as $item) { $row = $item['row']; @@ -397,7 +394,6 @@ class ContainerController extends Controller $markErrors = []; if (!empty($unmatchedMarks)) { - foreach ($cleanedRows as $item) { $row = $item['row']; $offset = $item['offset']; @@ -523,17 +519,19 @@ class ContainerController extends Controller $snap = $markToSnapshot[$firstMark] ?? null; $invoice = new Invoice(); - $invoice->container_id = $container->id; + $invoice->container_id = $container->id; // $invoice->customer_id = $customerId; - - // इथे Mark No सेट करतो - $invoice->mark_no = $firstMark; + $invoice->mark_no = $firstMark; $invoice->invoice_number = $this->generateInvoiceNumber(); - $invoice->invoice_date = now()->toDateString(); - // NEW (add this): - $invoice->due_date = Carbon::parse($invoice->invoice_date)->addDays(10)->format('Y-m-d'); + // invoice_date = container_date + $invoice->invoice_date = $container->container_date; + + // due_date = container_date + 10 days + $invoice->due_date = Carbon::parse($invoice->invoice_date) + ->addDays(10) + ->format('Y-m-d'); if ($snap) { $invoice->customer_name = $snap['customer_name'] ?? null; @@ -550,8 +548,8 @@ class ContainerController extends Controller $invoice->customer_address = null; $invoice->pincode = null; - $uniqueMarks = array_unique(array_column($rowsForCustomer, 'mark')); - $invoice->notes = 'Auto-created from Container ' . $container->container_number + $uniqueMarks = array_unique(array_column($rowsForCustomer, 'mark')); + $invoice->notes = 'Auto-created from Container ' . $container->container_number . ' for Mark(s): ' . implode(', ', $uniqueMarks); $invoice->pdf_path = null; $invoice->status = 'pending'; @@ -627,40 +625,120 @@ class ContainerController extends Controller ->where('id', $rowId) ->first(); - if (!$row) continue; + if (!$row) { + continue; + } - // original update + // 1) update container_rows.data $data = $row->data ?? []; foreach ($cols as $colHeader => $value) { $data[$colHeader] = $value; } - $row->update([ - 'data' => $data, - ]); + $row->update(['data' => $data]); + + // 2) normalize keys + $normalizedMap = []; + foreach ($data as $key => $value) { + if ($key === null || $key === '') { + continue; + } + + $normKey = strtoupper((string)$key); + $normKey = str_replace([' ', '/', '-', '.'], '', $normKey); + $normalizedMap[$normKey] = $value; + } + + // helper: get first numeric value from given keys + $getFirstNumeric = function (array $map, array $possibleKeys) { + foreach ($possibleKeys as $search) { + $normSearch = strtoupper($search); + $normSearch = str_replace([' ', '/', '-', '.'], '', $normSearch); + + foreach ($map as $nKey => $value) { + if (strpos($nKey, $normSearch) !== false) { + if (is_numeric($value)) { + return (float)$value; + } + if (is_string($value) && is_numeric(trim($value))) { + return (float)trim($value); + } + } + } + } + return 0; + }; + + // 3) read values – QTY vs TTLQTY separately + $ctnKeys = ['CTN', 'CTNS']; + $qtyKeys = ['QTY', 'PCS', 'PIECES']; // per-carton qty + $ttlQtyKeys = ['ITLQTY', 'TOTALQTY', 'TTLQTY']; // total qty + $cbmKeys = ['TOTALCBM', 'TTLCBM', 'ITLCBM', 'CBM']; + $kgKeys = ['TOTALKG', 'TTKG', 'KG', 'WEIGHT']; + $amountKeys = ['AMOUNT', 'TTLAMOUNT', 'TOTALAMOUNT']; + + $ctn = $getFirstNumeric($normalizedMap, $ctnKeys); + + // per carton qty + $qty = $getFirstNumeric($normalizedMap, $qtyKeys); + + // total qty direct from TOTALQTY/TTLQTY/ITLQTY + $ttlQ = $getFirstNumeric($normalizedMap, $ttlQtyKeys); + + // if total column is 0 then compute ctn * qty + if ($ttlQ == 0 && $ctn && $qty) { + $ttlQ = $ctn * $qty; + } + + $cbm = $getFirstNumeric($normalizedMap, ['CBM']); + $ttlC = $getFirstNumeric($normalizedMap, ['TOTALCBM', 'TTLCBM', 'ITLCBM']); + if ($ttlC == 0 && $cbm && $ctn) { + $ttlC = $cbm * $ctn; + } + + $kg = $getFirstNumeric($normalizedMap, ['KG', 'WEIGHT']); + $ttlK = $getFirstNumeric($normalizedMap, ['TOTALKG', 'TTKG']); + if ($ttlK == 0 && $kg && $ctn) { + $ttlK = $kg * $ctn; + } + + $price = $getFirstNumeric($normalizedMap, ['PRICE', 'RATE']); + $amount = $getFirstNumeric($normalizedMap, $amountKeys); + if ($amount == 0 && $price && $ttlQ) { + $amount = $price * $ttlQ; + } + + // 4) get description + $desc = null; + foreach (['DESCRIPTION', 'DESC'] as $dKey) { + $normD = str_replace([' ', '/', '-', '.'], '', strtoupper($dKey)); + foreach ($normalizedMap as $nKey => $v) { + if (strpos($nKey, $normD) !== false) { + $desc = is_string($v) ? trim($v) : $v; + break 2; + } + } + } - // extra: update linked invoice items & invoice totals $rowIndex = $row->row_index; - $ctn = (float) ($data['CTN'] ?? $data['CTNS'] ?? 0); - $qty = (float) ($data['QTY'] ?? 0); - $ttlQ = (float) ($data['TTLQTY'] ?? $data['TOTALQTY'] ?? $data['TTL/QTY'] ?? ($ctn * $qty)); - $price = (float) ($data['PRICE'] ?? 0); - $cbm = (float) ($data['CBM'] ?? 0); - $ttlC = (float) ($data['TOTALCBM'] ?? $data['TTL CBM'] ?? ($cbm * $ctn)); - $kg = (float) ($data['KG'] ?? 0); - $ttlK = (float) ($data['TOTALKG'] ?? $data['TTL KG'] ?? ($kg * $ctn)); - $amount = (float) ($data['AMOUNT'] ?? ($price * $ttlQ)); - $desc = $data['DESCRIPTION'] ?? $data['DESC'] ?? null; - + // 5) find linked invoice_items $items = InvoiceItem::where('container_id', $container->id) ->where('container_row_index', $rowIndex) ->get(); + if ($items->isEmpty() && $desc) { + $items = InvoiceItem::where('container_id', $container->id) + ->whereNull('container_row_index') + ->where('description', $desc) + ->get(); + } + + // 6) update invoice_items + recalc invoice totals foreach ($items as $item) { $item->description = $desc; $item->ctn = $ctn; - $item->qty = $qty; - $item->ttl_qty = $ttlQ; + $item->qty = $qty; // per carton + $item->ttl_qty = $ttlQ; // total $item->price = $price; $item->ttl_amount = $amount; $item->cbm = $cbm; @@ -703,33 +781,39 @@ class ContainerController extends Controller ->with('success', 'Excel rows updated successfully.'); } - // app/Http/Controllers/ContainerController.php -public function updateStatus(Request $request, Container $container) -{ - $request->validate([ - 'status' => 'required|in:pending,in-progress,completed,cancelled', - ]); - - $container->status = $request->status; - $container->save(); - - // जर AJAX असेल तर JSON दे - if ($request->wantsJson() || $request->ajax()) { - return response()->json([ - 'success' => true, - 'status' => $container->status, + public function updateStatus(Request $request, Container $container) + { + $request->validate([ + 'status' => 'required|in:container-ready,export-custom,international-transit,arrived-at-india,import-custom,warehouse,domestic-distribution,out-for-delivery,delivered', ]); + + $container->status = $request->status; + $container->save(); + + if ($request->wantsJson() || $request->ajax()) { + return response()->json([ + 'success' => true, + 'status' => $container->status, + ]); + } + + return back()->with('success', 'Container status updated.'); } - // normal form submit असेल तर redirect - return back()->with('success', 'Container status updated.'); -} - - public function destroy(Container $container) { $container->delete(); - return redirect()->route('containers.index')->with('success', 'Container deleted.'); + + if (request()->wantsJson() || request()->ajax()) { + return response()->json([ + 'success' => true, + 'message' => 'Container deleted', + ]); + } + + return redirect() + ->route('containers.index') + ->with('success', 'Container deleted.'); } private function generateInvoiceNumber(): string @@ -755,4 +839,105 @@ public function updateStatus(Request $request, Container $container) return 'INV-' . $year . '-' . str_pad($nextSeq, 6, '0', STR_PAD_LEFT); } + + public function downloadPdf(Container $container) + { + $container->load('rows'); + + $pdf = Pdf::loadView('admin.container_pdf', [ + 'container' => $container, + ])->setPaper('a4', 'landscape'); + + $fileName = 'container-'.$container->container_number.'.pdf'; + + return $pdf->download($fileName); + } + + public function downloadExcel(Container $container) + { + if (!$container->excel_file) { + abort(404, 'Excel file not found on record.'); + } + + // Stored path like "containers/abc.xlsx" + $path = $container->excel_file; + + if (!Storage::exists($path)) { + abort(404, 'Excel file missing on server.'); + } + + $fileName = 'container-'.$container->container_number.'.xlsx'; + + return Storage::download($path, $fileName); + } + + + public function popupPopup(Container $container) +{ + // existing show सारखाच data वापरू + $container->load('rows'); + + // summary आधीपासून index() मध्ये जसा काढतोस तसाच logic reuse + $rows = $container->rows ?? collect(); + + $totalCtn = 0; + $totalQty = 0; + $totalCbm = 0; + $totalKg = 0; + + $ctnKeys = ['CTN', 'CTNS']; + $qtyKeys = ['ITLQTY', 'TOTALQTY', 'TTLQTY', 'QTY', 'PCS', 'PIECES']; + $cbmKeys = ['TOTALCBM', 'TTLCBM', 'ITLCBM', 'CBM']; + $kgKeys = ['TOTALKG', 'TTKG', 'KG', 'WEIGHT']; + + $getFirstNumeric = function (array $data, array $possibleKeys) { + $normalizedMap = []; + foreach ($data as $key => $value) { + if ($key === null) continue; + $normKey = strtoupper((string)$key); + $normKey = str_replace([' ', ',', '-', '.', "\n", "\r", "\t"], '', $normKey); + $normalizedMap[$normKey] = $value; + } + + foreach ($possibleKeys as $search) { + $normSearch = strtoupper($search); + $normSearch = str_replace([' ', ',', '-', '.', "\n", "\r", "\t"], '', $normSearch); + + foreach ($normalizedMap as $nKey => $value) { + if (strpos($nKey, $normSearch) !== false) { + if (is_numeric($value)) { + return (float)$value; + } + if (is_string($value) && is_numeric(trim($value))) { + return (float)trim($value); + } + } + } + } + return 0; + }; + + foreach ($rows as $row) { + $data = $row->data ?? []; + if (!is_array($data)) continue; + + $totalCtn += $getFirstNumeric($data, $ctnKeys); + $totalQty += $getFirstNumeric($data, $qtyKeys); + $totalCbm += $getFirstNumeric($data, $cbmKeys); + $totalKg += $getFirstNumeric($data, $kgKeys); + } + + $summary = [ + 'total_ctn' => round($totalCtn, 2), + 'total_qty' => round($totalQty, 2), + 'total_cbm' => round($totalCbm, 3), + 'total_kg' => round($totalKg, 2), + ]; + + return view('admin.partials.container_popup_readonly', [ + 'container' => $container, + 'summary' => $summary, + ]); +} + } diff --git a/app/Models/InvoiceItem.php b/app/Models/InvoiceItem.php index d56ee0a..ee1f41e 100644 --- a/app/Models/InvoiceItem.php +++ b/app/Models/InvoiceItem.php @@ -11,6 +11,8 @@ class InvoiceItem extends Model protected $fillable = [ 'invoice_id', + 'container_id', // Container mapping + 'container_row_index', // Container row index 'description', 'ctn', @@ -38,7 +40,6 @@ class InvoiceItem extends Model return $this->belongsTo(Invoice::class); } - public function chargeGroupItems() { return $this->hasMany(InvoiceChargeGroupItem::class, 'invoice_item_id'); @@ -114,4 +115,3 @@ class InvoiceItem extends Model return $basis * $rate; } } - diff --git a/app/Models/User.php b/app/Models/User.php index 48c963c..d8afb94 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -89,10 +89,11 @@ class User extends Authenticatable implements JWTSubject { return []; } -public function invoices() -{ - return $this->hasMany(\App\Models\Invoice::class, 'customer_id', 'id'); -} + public function invoices() + { + return $this->hasMany(\App\Models\Invoice::class, 'customer_id', 'customer_id'); + } + // App\Models\User.php diff --git a/database/migrations/2026_02_07_132057_add_status_to_containers_table.php b/database/migrations/2026_02_07_132057_add_status_to_containers_table.php index 314efcf..5396830 100644 --- a/database/migrations/2026_02_07_132057_add_status_to_containers_table.php +++ b/database/migrations/2026_02_07_132057_add_status_to_containers_table.php @@ -9,7 +9,7 @@ return new class extends Migration public function up(): void { Schema::table('containers', function (Blueprint $table) { - $table->string('status', 20) + $table->string('status', 21) ->default('pending') ->after('container_date'); }); diff --git a/database/migrations/2026_02_28_051812_add_duedate_to_invoices_table.php b/database/migrations/2026_02_28_051812_add_duedate_to_invoices_table.php index 986a450..5504352 100644 --- a/database/migrations/2026_02_28_051812_add_duedate_to_invoices_table.php +++ b/database/migrations/2026_02_28_051812_add_duedate_to_invoices_table.php @@ -6,21 +6,24 @@ use Illuminate\Support\Facades\Schema; return new class extends Migration { - /** - * Run the migrations. - */ - public function up() + public function up(): void { Schema::table('invoices', function (Blueprint $table) { - $table->date('duedate')->nullable()->after('invoicedate'); + // column आधीच आहे का हे check करून, नसेल तरच add करायचा + if (!Schema::hasColumn('invoices', 'due_date')) { + $table->date('due_date') + ->nullable() + ->after('invoice_date'); + } }); } - - public function down() + + public function down(): void { Schema::table('invoices', function (Blueprint $table) { - $table->dropColumn('duedate'); + if (Schema::hasColumn('invoices', 'due_date')) { + $table->dropColumn('due_date'); + } }); } - }; diff --git a/database/migrations/2026_03_01_075242_alter_status_length_on_containers_table.php b/database/migrations/2026_03_01_075242_alter_status_length_on_containers_table.php new file mode 100644 index 0000000..5eaa1a4 --- /dev/null +++ b/database/migrations/2026_03_01_075242_alter_status_length_on_containers_table.php @@ -0,0 +1,26 @@ +string('status', 50)->change(); + }); +} + +public function down(): void +{ + Schema::table('containers', function (Blueprint $table) { + $table->string('status', 20)->change(); + }); +} + +}; diff --git a/public/invoices/invoice-INV-2026-000110.pdf b/public/invoices/invoice-INV-2026-000110.pdf new file mode 100644 index 0000000..40b4775 Binary files /dev/null and b/public/invoices/invoice-INV-2026-000110.pdf differ diff --git a/public/invoices/invoice-INV-2026-000116.pdf b/public/invoices/invoice-INV-2026-000116.pdf new file mode 100644 index 0000000..6101382 Binary files /dev/null and b/public/invoices/invoice-INV-2026-000116.pdf differ diff --git a/public/invoices/invoice-INV-2026-000117.pdf b/public/invoices/invoice-INV-2026-000117.pdf new file mode 100644 index 0000000..a53b097 Binary files /dev/null and b/public/invoices/invoice-INV-2026-000117.pdf differ diff --git a/public/invoices/invoice-INV-2026-000134.pdf b/public/invoices/invoice-INV-2026-000134.pdf new file mode 100644 index 0000000..04b1d4a Binary files /dev/null and b/public/invoices/invoice-INV-2026-000134.pdf differ diff --git a/resources/views/admin/Partials/container_popup_readonly.blade.php b/resources/views/admin/Partials/container_popup_readonly.blade.php new file mode 100644 index 0000000..88058ad --- /dev/null +++ b/resources/views/admin/Partials/container_popup_readonly.blade.php @@ -0,0 +1,102 @@ +
+ + {{-- Top info cards (container / date / status) --}} +
+
+
+ Container Name +
{{ $container->container_name ?? '-' }}
+
+
+
+
+ Container No +
{{ $container->container_number ?? '-' }}
+
+
+
+
+ Container Date +
+ {{ $container->container_date ? \Carbon\Carbon::parse($container->container_date)->format('d-m-Y') : '-' }} +
+
+
+
+
+ Status +
{{ $container->status ?? '-' }}
+
+
+
+ + {{-- Totals (CTN / Qty / CBM / KG) --}} +
+
+
+ Total CTN +
{{ $summary['total_ctn'] ?? '-' }}
+
+
+
+
+ Total Qty +
{{ $summary['total_qty'] ?? '-' }}
+
+
+
+
+ Total CBM +
{{ $summary['total_cbm'] ?? '-' }}
+
+
+
+
+ Total KG +
{{ $summary['total_kg'] ?? '-' }}
+
+
+
+ + {{-- Excel rows – same headings as container_show --}} + @php + $allHeadings = []; + foreach ($container->rows as $row) { + if (is_array($row->data)) { + $allHeadings = array_unique(array_merge($allHeadings, array_keys($row->data))); + } + } + @endphp + +
+ + + + + @foreach($allHeadings as $heading) + + @endforeach + + + + @forelse($container->rows as $index => $row) + + + @foreach($allHeadings as $heading) + @php + $val = is_array($row->data) ? ($row->data[$heading] ?? '') : ''; + @endphp + + @endforeach + + @empty + + + + @endforelse + +
#{{ $heading }}
{{ $index + 1 }}{{ $val }}
+ No Excel rows for this container. +
+
+
diff --git a/resources/views/admin/account.blade.php b/resources/views/admin/account.blade.php index db330cf..b2d95ee 100644 --- a/resources/views/admin/account.blade.php +++ b/resources/views/admin/account.blade.php @@ -2603,11 +2603,12 @@ function renderPaymentTable(list){ ${escapeHtml(entry.entry_date)} ${escapeHtml(entry.description)} + - + ${escapeHtml(entry.region)} @@ -2680,7 +2681,6 @@ function renderPaymentTable(list){ - function cycleToggle(btn) { // वर्तमान position घेऊन पुढचा स्टेट कॅल्क्युलेट करा let pos = parseInt(btn.dataset.pos || '0', 10); // 0 = unpaid, 1 = pending, 2 = paid diff --git a/resources/views/admin/container.blade.php b/resources/views/admin/container.blade.php index 4e8298d..a64fdb3 100644 --- a/resources/views/admin/container.blade.php +++ b/resources/views/admin/container.blade.php @@ -98,9 +98,7 @@ gap: 10px; } - .filter-title i { - color: var(--primary-color); - } + .filter-title i { color: var(--primary-color); } .filter-grid { display: grid; @@ -108,9 +106,7 @@ gap: 15px; } - .filter-group { - position: relative; - } + .filter-group { position: relative; } .filter-group label { display: block; @@ -139,9 +135,7 @@ box-shadow: 0 0 0 3px rgba(76, 111, 255, 0.1); } - .filter-input::placeholder { - color: #94a3b8; - } + .filter-input::placeholder { color: #94a3b8; } .filter-actions { display: flex; @@ -212,9 +206,7 @@ gap: 12px; } - .card-header h2 i { - color: white; - } + .card-header h2 i { color: white; } .stats-badge { background: rgba(255, 255, 255, 0.2); @@ -239,9 +231,7 @@ transform: translateX(4px); } - .container-item:last-child { - border-bottom: none; - } + .container-item:last-child { border-bottom: none; } .container-header { display: flex; @@ -297,40 +287,92 @@ color: #94a3b8; } - .status-badge { - padding: 6px 16px; - border-radius: 20px; - font-size: 12px; + /* STATUS DROPDOWN (badge look) */ + .status-dropdown { + position: relative; + min-width: 190px; + cursor: pointer; + } + + .status-dropdown-toggle { + padding: 8px 16px; + border-radius: 999px; + border: 1px solid var(--border-color); + background: #ffffff; + font-size: 13px; font-weight: 600; - letter-spacing: 0.3px; - display: inline-flex; + color: var(--dark-text); + display: flex; align-items: center; + justify-content: space-between; gap: 6px; } - .status-badge i { - font-size: 10px; + .status-dropdown-toggle span { white-space: nowrap; } + + .status-dropdown-menu { + position: absolute; + top: -230%; + right: 0; + z-index: 30; + background: #ffffff; + border-radius: 14px; + padding: 8px 0; + box-shadow: var(--shadow-lg); + border: 1px solid var(--border-color); + width: 220px; + max-height: 340px; + overflow-y: auto; + display: none; } - .status-pending { - background: #fef3c7; - color: #d97706; + .status-dropdown-menu.open { display: block; } + + .status-option { + padding: 6px 14px; + font-size: 13px; + color: var(--dark-text); + cursor: pointer; + display: flex; + align-items: center; + gap: 8px; + transition: background 0.15s; + line-height: 1.3; } - .status-in-progress { - background: #dbeafe; - color: #1d4ed8; + .status-option:hover { background: #eef2ff; } + + .status-option .dot { + width: 8px; + height: 8px; + border-radius: 999px; + background: #9ca3af; } - .status-completed { - background: #d1fae5; - color: #065f46; + .status-option.active .dot { + background: #22c55e; } - .status-cancelled { - background: #fee2e2; - color: #991b1b; - } + /* COLOR MAPPING per status – dropdown tint + main toggle text color */ + .status-option.status-container-ready { background: #eff6ff; color: #1d4ed8; } + .status-option.status-export-custom { background: #fff7ed; color: #b45309; } + .status-option.status-international-transit { background: #f5f3ff; color: #4c1d95; } + .status-option.status-arrived-at-india { background: #ecfdf5; color: #15803d; } + .status-option.status-import-custom { background: #fffbeb; color: #92400e; } + .status-option.status-warehouse { background: #f4f4f5; color: #374151; } + .status-option.status-domestic-distribution { background: #faf5ff; color: #6d28d9; } + .status-option.status-out-for-delivery { background: #eff6ff; color: #1d4ed8; } + .status-option.status-delivered { background: #ecfdf5; color: #15803d; } + + .status-dropdown-toggle.status-container-ready { background: #eff6ff; color: #1d4ed8; } + .status-dropdown-toggle.status-export-custom { background: #fff7ed; color: #b45309; } + .status-dropdown-toggle.status-international-transit { background: #f5f3ff; color: #4c1d95; } + .status-dropdown-toggle.status-arrived-at-india { background: #ecfdf5; color: #15803d; } + .status-dropdown-toggle.status-import-custom { background: #fffbeb; color: #92400e; } + .status-dropdown-toggle.status-warehouse { background: #f4f4f5; color: #374151; } + .status-dropdown-toggle.status-domestic-distribution { background: #faf5ff; color: #6d28d9; } + .status-dropdown-toggle.status-out-for-delivery { background: #eff6ff; color: #1d4ed8; } + .status-dropdown-toggle.status-delivered { background: #ecfdf5; color: #15803d; } .action-buttons { display: flex; @@ -373,39 +415,7 @@ color: white; } - .update-form { - display: flex; - align-items: center; - gap: 8px; - } - - .status-select { - padding: 8px 12px; - border: 1px solid var(--border-color); - border-radius: var(--radius-md); - font-size: 13px; - color: var(--dark-text); - background: white; - min-width: 140px; - cursor: pointer; - } - - .update-btn { - background: var(--primary-color); - color: white; - border: none; - padding: 8px 16px; - border-radius: var(--radius-md); - font-size: 13px; - font-weight: 600; - cursor: pointer; - transition: all 0.3s ease; - white-space: nowrap; - } - - .update-btn:hover { - background: #3b5de6; - } + .update-form { position: relative; } .no-results { text-align: center; @@ -444,16 +454,13 @@ animation: slideIn 0.3s ease; } - .success-message i { - font-size: 20px; - } + .success-message i { font-size: 20px; } @keyframes slideIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } - /* 🔥 Totals section */ .totals-section { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); @@ -504,9 +511,7 @@ width: 100%; justify-content: center; } - .filter-grid { - grid-template-columns: 1fr; - } + .filter-grid { grid-template-columns: 1fr; } .container-header { flex-direction: column; align-items: flex-start; @@ -519,13 +524,8 @@ } @media (max-width: 576px) { - .update-form { - flex-direction: column; - width: 100%; - } - .status-select, .update-btn { - width: 100%; - } + .update-form { width: 100%; } + .status-dropdown { width: 100%; } } @@ -569,10 +569,15 @@ @@ -610,22 +615,31 @@

Get started by creating your first container

@else + @php + $labels = [ + 'container-ready' => 'Container Ready', + 'export-custom' => 'Export Custom', + 'international-transit' => 'International Transit', + 'arrived-at-india' => 'Arrived at India', + 'import-custom' => 'Import Custom', + 'warehouse' => 'Warehouse', + 'domestic-distribution' => 'Domestic Distribution', + 'out-for-delivery' => 'Out for Delivery', + 'delivered' => 'Delivered', + ]; + @endphp + @foreach($containers as $container) @php - $status = $container->status; - $statusClass = match ($status) { - 'completed' => 'status-completed', - 'in-progress' => 'status-in-progress', - 'cancelled' => 'status-cancelled', - default => 'status-pending', - }; + $status = $container->status ?? 'container-ready'; + $statusLabel = $labels[$status] ?? ucfirst(str_replace('-', ' ', $status)); @endphp
- {{ substr($container->container_name, 0, 2) }} + {{ strtoupper(substr($container->container_name, 0, 2)) }}

{{ $container->container_name }}

@@ -647,51 +661,56 @@
- - - - {{ ucfirst(str_replace('-', ' ', $status)) }} - - - - - @can('container.update') - - View - - @endcan - @can('containers.update_status')
+ method="POST" + class="update-form ajax-status-form" + data-container-id="{{ $container->id }}"> @csrf - + + @php $statusClass = 'status-' . $status; @endphp + +
+
+ + {{ $statusLabel }} + + +
+
+ @foreach($labels as $value => $label) + @php $optClass = 'status-' . $value; @endphp +
+ + {{ $label }} +
+ @endforeach +
+
- @endcan - + @endcan + @can('container.update') + + View + + @endcan @can('container.delete') -
- @csrf - @method('DELETE') - -
+
+ @csrf + @method('DELETE') + +
@endcan
-
{{ number_format($container->summary['total_ctn'], 1) }}
@@ -716,87 +735,121 @@
- - - - - - - - - @endsection diff --git a/resources/views/admin/container_create.blade.php b/resources/views/admin/container_create.blade.php index f947a4d..158de77 100644 --- a/resources/views/admin/container_create.blade.php +++ b/resources/views/admin/container_create.blade.php @@ -137,6 +137,10 @@ Some rows in your Excel file have formula or mark issues. See the table below, and detailed messages after the table.
+
@@ -183,11 +187,9 @@ - {{-- Formula error rows --}} + {{-- Formula error rows (red – formula mismatch, critical) --}} @foreach($formulaErrors as $fe) - @php - $rowData = $fe['data'] ?? []; - @endphp + @php $rowData = $fe['data'] ?? []; @endphp @if(!empty($rowData)) {{ $fe['excel_row'] }} @@ -199,11 +201,9 @@ @endif @endforeach - {{-- Mark error rows --}} + {{-- Mark error rows (yellow – mark not found, warning) --}} @foreach($markErrors as $me) - @php - $rowData = $me['data'] ?? []; - @endphp + @php $rowData = $me['data'] ?? []; @endphp @if(!empty($rowData)) {{ $me['excel_row'] }} @@ -292,7 +292,9 @@
-
@@ -322,4 +324,26 @@ + + + @endsection diff --git a/resources/views/admin/container_pdf.blade.php b/resources/views/admin/container_pdf.blade.php new file mode 100644 index 0000000..e159674 --- /dev/null +++ b/resources/views/admin/container_pdf.blade.php @@ -0,0 +1,202 @@ + + + + + Container {{ $container->container_number }} Summary + + + +@php + $totalCtn = 0; + $totalQty = 0; + $totalCbm = 0.0; + $totalKg = 0.0; + + foreach ($container->rows as $row) { + if (!is_array($row->data)) continue; + foreach ($row->data as $h => $v) { + $norm = strtoupper(str_replace([' ', '/', '-', '.'],'', $h)); + $val = is_numeric(str_replace([','], '', $v)) ? floatval(str_replace([','], '', $v)) : 0; + + if (str_contains($norm, 'TOTALCTN') || $norm === 'CTN' || str_contains($norm,'TOTALCNTR') || str_contains($norm,'TOTALCARTON')) { + $totalCtn += $val; + } + if (str_contains($norm,'TOTALQTY') || str_contains($norm,'ITLQTY') || str_contains($norm,'TTLQTY')) { + $totalQty += $val; + } + if (str_contains($norm,'TOTALCBM') || str_contains($norm,'TTLCBM') || str_contains($norm,'ITLCBM')) { + $totalCbm += $val; + } + if (str_contains($norm,'TOTALKG') || str_contains($norm,'TTKG')) { + $totalKg += $val; + } + } + } + + $allHeadings = []; + foreach ($container->rows as $row) { + if (is_array($row->data)) { + $allHeadings = array_unique(array_merge($allHeadings, array_keys($row->data))); + } + } +@endphp + +{{-- TWO ROW GRID – FIRST: INFO / SECOND: TOTALS --}} +
+
+
+
Container ID
+
{{ $container->id }}
+
+
+
Container Number
+
{{ $container->container_number }}
+
+
+
Container Date
+
+ {{ $container->container_date ? $container->container_date->format('d-m-Y') : '-' }} +
+
+
+
Container Name
+
+ {{ $container->container_name ?? '-' }} +
+
+
+ +
+
+
Total CTN
+
{{ number_format($totalCtn, 0) }}
+
+
+
Total QTY
+
{{ number_format($totalQty, 0) }}
+
+
+
Total CBM
+
{{ number_format($totalCbm, 3) }}
+
+
+
Total KG
+
{{ number_format($totalKg, 2) }}
+
+
+
+ +{{-- FULL TABLE --}} + + + + + @foreach($allHeadings as $heading) + + @endforeach + + + + @foreach($container->rows as $index => $row) + + + @foreach($allHeadings as $heading) + + @endforeach + + @endforeach + +
#{{ $heading }}
{{ $index + 1 }}{{ $row->data[$heading] ?? '' }}
+ + diff --git a/resources/views/admin/container_show.blade.php b/resources/views/admin/container_show.blade.php index 2010f18..05b2326 100644 --- a/resources/views/admin/container_show.blade.php +++ b/resources/views/admin/container_show.blade.php @@ -6,7 +6,13 @@
- - {{-- TOP GRADIENT HEADER --}}
-

- Container: {{ $container->container_number }} -

+

Container {{ $container->container_number }}

- Edit loading list directly — scroll horizontally & vertically like Excel. + Edit loading list directly – like Excel. TT columns auto‑calculate from CTN, QTY, CBM, KG, PRICE.
- - ← Back to list - +
- {{-- MAIN CARD --}}
-
Container Information
- @if(!$container->rows->isEmpty()) - - @endif
- {{-- INFO STRIP --}} -
-
-
Container
-
{{ $container->container_name }}
-
-
-
Date
-
{{ $container->container_date?->format('d-m-Y') }}
-
-
-
Excel File
- @if($container->excel_file) -
- - 📄 Download / View - + {{-- 3 INFO CARDS IN SINGLE ROW --}} +
+
+
+ +
+
+
Container
+
+ {{ $container->container_name ?? $container->container_number }}
- @else -
Not uploaded
- @endif +
+
+ +
+
+ +
+
+
Date
+
+ {{ $container->container_date ? $container->container_date->format('d-m-Y') : '' }} +
+
+
+ +
+
+ +
+
+
Excel File
+
+ @if($container->excel_file) + + Download / View + + @else + Not uploaded + @endif +
+
+ @php + $totalCtn = 0; + $totalQty = 0; + $totalCbm = 0.0; + $totalKg = 0.0; + + if(!$container->rows->isEmpty()){ + foreach ($container->rows as $row) { + if (!is_array($row->data)) continue; + foreach ($row->data as $h => $v) { + $norm = strtoupper(str_replace([' ', '/', '-', '.'],'', $h)); + $val = is_numeric(str_replace([','], '', $v)) ? floatval(str_replace([','], '', $v)) : 0; + + if (str_contains($norm, 'TOTALCTN') || $norm === 'CTN' || str_contains($norm,'TOTALCNTR') || str_contains($norm,'TOTALCARTON')) { + $totalCtn += $val; + } + + if ( + str_contains($norm,'TOTALQTY') || + str_contains($norm,'ITLQTY') || + str_contains($norm,'TTLQTY') + ) { + $totalQty += $val; + } + + if ( + str_contains($norm,'TOTALCBM') || + str_contains($norm,'TTLCBM') || + str_contains($norm,'ITLCBM') + ) { + $totalCbm += $val; + } + + if ( + str_contains($norm,'TOTALKG') || + str_contains($norm,'TTKG') + ) { + $totalKg += $val; + } + } + } + } + @endphp + + @if(!$container->rows->isEmpty()) +
+
+
+ +
+
+
Total CTN
+
+ {{ number_format($totalCtn, 0) }} +
+
+
+ +
+
+ +
+
+
Total QTY
+
+ {{ number_format($totalQty, 0) }} +
+
+
+ +
+
+ +
+
+
Total CBM
+
+ {{ number_format($totalCbm, 3) }} +
+
+
+ +
+
+ +
+
+
Total KG
+
+ {{ number_format($totalKg, 2) }} +
+
+
+
+ @endif + @if($container->rows->isEmpty())
No entries found for this container.
@else @@ -333,60 +606,114 @@ } @endphp - {{-- FILTER BAR --}}
- Total rows: {{ $container->rows->count() }}  •  Edit cells then click "Save Changes" + Total rows: {{ $container->rows->count() }}    Edit cells then click "Save Changes". - +
- {{-- EDITABLE TABLE FORM --}} -
+ @csrf -
-
- - +
+
+ @foreach($allHeadings as $heading) @endforeach - - + + @foreach($container->rows as $index => $row) @foreach($allHeadings as $heading) - @php $value = $row->data[$heading] ?? ''; @endphp + @php + $value = $row->data[$heading] ?? ''; + + $norm = strtoupper(str_replace([' ', '/', '-', '.'],'', $heading)); + + $isCtn = str_contains($norm, 'CTN'); + + $isTotalQty = ( + str_contains($norm, 'TOTALQTY') || + str_contains($norm, 'ITLQTY') || + str_contains($norm, 'TTLQTY') + ); + $isQty = !$isTotalQty && ( + str_contains($norm, 'QTY') || + str_contains($norm, 'PCS') || + str_contains($norm, 'PIECES') + ); + + $isTotalCbm = ( + str_contains($norm, 'TOTALCBM') || + str_contains($norm, 'TTLCBM') || + str_contains($norm, 'ITLCBM') + ); + $isCbm = !$isTotalCbm && str_contains($norm, 'CBM'); + + $isTotalKg = ( + str_contains($norm, 'TOTALKG') || + str_contains($norm, 'TTKG') + ); + $isKg = !$isTotalKg && (str_contains($norm, 'KG') || str_contains($norm, 'WEIGHT')); + + $isPrice = (str_contains($norm, 'PRICE') || str_contains($norm, 'RATE')); + + $isAmount = ( + str_contains($norm, 'AMOUNT') || + str_contains($norm, 'TTLAMOUNT') || + str_contains($norm, 'TOTALAMOUNT') + ); + + $isTotalColumn = $isTotalQty || $isTotalCbm || $isTotalKg || $isAmount; + @endphp @endforeach @endforeach - -
#{{ $heading }}
{{ $index + 1 }} - +
-
+ + +
@endif
-
+@if(!$container->rows->isEmpty()) + +
+ Changes saved successfully. +
+@endif + @endsection diff --git a/resources/views/admin/customers.blade.php b/resources/views/admin/customers.blade.php index 31db1f2..8feb33f 100644 --- a/resources/views/admin/customers.blade.php +++ b/resources/views/admin/customers.blade.php @@ -10,7 +10,7 @@ body { font-family: 'Inter', sans-serif; - overflow-x: hidden; /* Prevent horizontal scroll on body */ + overflow-x: hidden; } .glass-card { @@ -22,7 +22,6 @@ overflow: hidden; } - /* New Stats Container */ .stats-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); @@ -43,9 +42,7 @@ min-height: 70px; } - .stat-card:hover { - transform: translateY(-2px); - } + .stat-card:hover { transform: translateY(-2px); } .stat-card.warning { border-left-color: #f59e0b; @@ -57,16 +54,6 @@ background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%); } - .stat-card.danger { - border-left-color: #ef4444; - background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%); - } - - .stat-card.info { - border-left-color: #3b82f6; - background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); - } - .stat-card.secondary { border-left-color: #8b5cf6; background: linear-gradient(135deg, #faf5ff 0%, #f3e8ff 100%); @@ -91,46 +78,19 @@ .stat-card.warning .stat-icon { background: rgba(245, 158, 11, 0.1); } - - .stat-card.warning .stat-icon i { - color: #f59e0b; - } + .stat-card.warning .stat-icon i { color: #f59e0b; } .stat-card.success .stat-icon { background: rgba(16, 185, 129, 0.1); } - - .stat-card.success .stat-icon i { - color: #10b981; - } - - .stat-card.danger .stat-icon { - background: rgba(239, 68, 68, 0.1); - } - - .stat-card.danger .stat-icon i { - color: #ef4444; - } - - .stat-card.info .stat-icon { - background: rgba(59, 130, 246, 0.1); - } - - .stat-card.info .stat-icon i { - color: #3b82f6; - } + .stat-card.success .stat-icon i { color: #10b981; } .stat-card.secondary .stat-icon { background: rgba(139, 92, 246, 0.1); } + .stat-card.secondary .stat-icon i { color: #8b5cf6; } - .stat-card.secondary .stat-icon i { - color: #8b5cf6; - } - - .stat-content { - flex: 1; - } + .stat-content { flex: 1; } .stat-value { font-size: 22px; @@ -147,14 +107,13 @@ line-height: 1.3; } - /* Updated Search Container - Wider with icon on left */ .search-container { background: rgba(255, 255, 255, 0.9); border-radius: 10px; padding: 6px 12px; border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); - width: 350px; /* Increased width */ + width: 350px; display: flex; align-items: center; } @@ -210,7 +169,6 @@ font-family: 'Inter', sans-serif; } - /* Updated Table Styles - Fixed horizontal scroll */ .table-glass { background: rgba(255, 255, 255, 0.9); border-radius: 10px; @@ -219,7 +177,6 @@ font-family: 'Inter', sans-serif; } - /* Single gradient for entire header - Blue to Purple */ .table thead { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; } @@ -232,20 +189,9 @@ border: none; font-family: 'Inter', sans-serif; position: relative; - background: linear-gradient(135deg, #667eea 0%);; - + background: linear-gradient(135deg, #667eea 0%); } - /* Remove individual curved borders */ - .table-header:first-child { - border-top-left-radius: 0; - } - - .table-header:last-child { - border-top-right-radius: 0; - } - - /* Apply rounded corners to the entire header container */ .table-container thead tr:first-child th:first-child { border-top-left-radius: 10px; } @@ -254,7 +200,6 @@ border-top-right-radius: 10px; } - /* Updated Table Column Alignment */ .table > :not(caption) > * > * { padding: 14px 12px; border-bottom: 1px solid rgba(0, 0, 0, 0.05); @@ -263,44 +208,35 @@ vertical-align: middle; } - /* Center align specific columns */ - .table > :not(caption) > * > *:nth-child(2), /* Customer ID */ - .table > :not(caption) > * > *:nth-child(3), /* Orders */ - .table > :not(caption) > * > *:nth-child(4), /* Total */ - .table > :not(caption) > * > *:nth-child(5) { /* Create Date */ + .table > :not(caption) > * > *:nth-child(2), + .table > :not(caption) > * > *:nth-child(3), + .table > :not(caption) > * > *:nth-child(4), + .table > :not(caption) > * > *:nth-child(5) { text-align: center; } - /* Customer Info column should remain left-aligned */ - .table > :not(caption) > * > *:first-child { - text-align: left; - } + .table > :not(caption) > * > *:first-child { text-align: left; } - /* Status and Actions columns should remain as is */ - .table > :not(caption) > * > *:nth-child(6), /* Status */ - .table > :not(caption) > * > *:nth-child(7) { /* Actions */ + .table > :not(caption) > * > *:nth-child(6), + .table > :not(caption) > * > *:nth-child(7), + .table > :not(caption) > * > *:nth-child(8), + .table > :not(caption) > * > *:nth-child(9) { text-align: center; } - - /* Updated header alignment to match */ + .table-header:nth-child(2), .table-header:nth-child(3), .table-header:nth-child(4), - .table-header:nth-child(5) { - text-align: center; - } - - /* Customer Info header stays left */ - .table-header:first-child { - text-align: Center; - } - - /* Status and Actions headers stay centered */ + .table-header:nth-child(5), .table-header:nth-child(6), - .table-header:nth-child(7) { + .table-header:nth-child(7), + .table-header:nth-child(8), + .table-header:nth-child(9) { text-align: center; } + .table-header:first-child { text-align: Center; } + .customer-avatar { width: 40px; height: 40px; @@ -374,7 +310,7 @@ .customer-info-column { min-width: 220px; - max-width: 220px; /* Added max-width to prevent overflow */ + max-width: 220px; } .table tbody tr { @@ -391,31 +327,25 @@ color: #6c757d; } - /* Remove customer-stats since we're adding columns */ - - /* Enhanced table styling - Fixed horizontal scroll */ .table-container { border-radius: 10px; overflow: hidden; - width: 100%; /* Ensure container takes full width */ + width: 100%; } - /* Fix table responsiveness */ .table-responsive { overflow-x: auto; -webkit-overflow-scrolling: touch; width: 100%; } - /* Ensure table doesn't exceed container */ .table { width: 100%; max-width: 100%; margin-bottom: 0; - table-layout: auto; /* Changed to auto for better column distribution */ + table-layout: auto; } - /* Fix for search and filter section */ .search-filter-container { display: flex; align-items: center; @@ -439,11 +369,10 @@ flex-shrink: 0; } - /* New columns styling */ .orders-column, .total-column, .customer-id-column, .create-date-column { text-align: center; font-weight: 500; - min-width: 80px; /* Added minimum widths for consistency */ + min-width: 80px; } .orders-count { @@ -458,7 +387,6 @@ font-weight: 600; } - /* ---------- Pagination Styles ---------- */ .pagination-container { display: flex; justify-content: space-between; @@ -485,14 +413,10 @@ justify-content: flex-end; } - .pagination-btn { + .pagination-img-btn { background: #fff; border: 1px solid #e3eaf6; - color: #1a2951; - padding: 8px 12px; border-radius: 6px; - font-size: 13px; - font-weight: 600; cursor: pointer; transition: all 0.3s ease; display: flex; @@ -500,20 +424,19 @@ justify-content: center; min-width: 40px; height: 32px; + padding: 0; } - .pagination-btn:hover:not(:disabled) { + .pagination-img-btn:hover:not(:disabled) { background: #1a2951; - color: white; border-color: #1a2951; } - .pagination-btn:disabled { + .pagination-img-btn:disabled { background: #f8fafc; - color: #cbd5e0; border-color: #e2e8f0; cursor: not-allowed; - opacity: 0.6; + opacity: 0.5; } .pagination-page-btn { @@ -551,61 +474,11 @@ flex-wrap: wrap; } - .pagination-ellipsis { - color: #9ba5bb; - font-size: 13px; - padding: 0 4px; - } - - /* Image-based pagination buttons */ - .pagination-img-btn { - background: #fff; - border: 1px solid #e3eaf6; - border-radius: 6px; - cursor: pointer; - transition: all 0.3s ease; - display: flex; - align-items: center; - justify-content: center; - min-width: 40px; - height: 32px; - padding: 0; - } - - .pagination-img-btn:hover:not(:disabled) { - background: #1a2951; - border-color: #1a2951; - } - - .pagination-img-btn:disabled { - background: #f8fafc; - border-color: #e2e8f0; - cursor: not-allowed; - opacity: 0.5; - } - - .pagination-img-btn img { - width: 16px; - height: 16px; - filter: brightness(0) saturate(100%) invert(26%) sepia(89%) saturate(748%) hue-rotate(201deg) brightness(93%) contrast(89%); - transition: filter 0.3s ease; - } - - .pagination-img-btn:hover:not(:disabled) img { - filter: brightness(0) saturate(100%) invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(106%) contrast(101%); - } - - .pagination-img-btn:disabled img { - filter: brightness(0) saturate(100%) invert(84%) sepia(8%) saturate(165%) hue-rotate(179deg) brightness(89%) contrast(86%); - } - - /* Mobile responsive fixes */ @media (max-width: 1200px) { .table > :not(caption) > * > * { padding: 12px 8px; font-size: 13px; } - .customer-info-column { min-width: 180px; max-width: 180px; @@ -613,65 +486,42 @@ } @media (max-width: 992px) { - .search-container { - width: 280px; - } - - .stats-container { - grid-template-columns: repeat(2, 1fr); - } + .search-container { width: 280px; } + .stats-container { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 768px) { - .stats-container { - grid-template-columns: repeat(2, 1fr); - } - + .stats-container { grid-template-columns: repeat(2, 1fr); } .search-filter-container { flex-direction: column; align-items: stretch; gap: 10px; } - - .search-section { - justify-content: center; - } - - .search-container { - width: 100%; - } - + .search-section { justify-content: center; } + .search-container { width: 100%; } .filter-section { justify-content: center; flex-wrap: wrap; } - .pagination-container { flex-direction: column; gap: 10px; align-items: stretch; } - - .pagination-controls { - justify-content: center; - } - + .pagination-controls { justify-content: center; } .table > :not(caption) > * > * { padding: 10px 6px; font-size: 12px; } - .customer-info-column { min-width: 150px; max-width: 150px; } - .customer-avatar { width: 32px; height: 32px; font-size: 0.8rem; } - .action-btn { width: 26px; height: 26px; @@ -680,19 +530,12 @@ } @media (max-width: 576px) { - .stats-container { - grid-template-columns: 1fr; - } - - .table-responsive { - font-size: 12px; - } - + .stats-container { grid-template-columns: 1fr; } + .table-responsive { font-size: 12px; } .customer-info-column { min-width: 120px; max-width: 120px; } - .premium-badge, .regular-badge, .status-badge { @@ -703,14 +546,11 @@
-

Customer List

-
-
@@ -721,7 +561,6 @@
-
@@ -739,7 +578,6 @@
-
@@ -755,7 +593,6 @@
-
@@ -772,10 +609,8 @@
-
-
@@ -792,7 +627,6 @@
-
-
@@ -828,8 +661,8 @@ - {{-- NEW --}} - {{-- NEW --}} + + @@ -839,113 +672,106 @@ @forelse($customers as $c) @php - // Invoice total (with GST) - $totalPayable = $c->invoices->sum('final_amount_with_gst'); + // Orders = invoice count + $ordersCount = $c->invoices->count(); + + // Order Total = items total from all invoices (final_amount) + $orderTotal = $c->invoices->sum('final_amount'); + + // Total payable = grand total with GST + groups + $totalPayable = $c->invoices->sum('grand_total_with_charges'); // Total paid via installments - $totalPaid = $c->invoices - ->flatMap(fn($inv) => $inv->installments) - ->sum('amount'); + $totalPaid = $c->invoiceInstallments->sum('amount'); // Remaining amount $remainingAmount = max($totalPayable - $totalPaid, 0); @endphp - - - + + - - + - - + - - - - - - + + + + - + + - - + - - - - + + @csrf + + + + + @empty - @@ -956,14 +782,12 @@ -
Showing {{ $customers->firstItem() ?? 0 }} to {{ $customers->lastItem() ?? 0 }} of {{ $customers->total() }} entries
-
+ +
+ + -
- + +
+ +
-
- - to - -
-
-
- - - - - - + +
+
+ + +
+ to +
+ + +
+
+ +
@@ -1181,77 +1211,107 @@
Customer ID Orders Order TotalTotal PayableRemainingTotal PayableRemaining Create Date Status Actions
-
-
- {{ strtoupper(substr($c->customer_name,0,1)) }} -
-
-
{{ $c->customer_name }}
- @if($c->customer_type == 'premium') - Premium Customer - @else - Regular Customer - @endif -
- {{ $c->email }}
- {{ $c->mobile_no }} +
+
+
+ {{ strtoupper(substr($c->customer_name,0,1)) }} +
+
+
{{ $c->customer_name }}
+ @if($c->customer_type == 'premium') + Premium Customer + @else + Regular Customer + @endif +
+ {{ $c->email }}
+ {{ $c->mobile_no }} +
- -
- {{ $c->customer_id }} - + {{ $c->customer_id }} + - {{ $c->orders->count() }} - + {{ $ordersCount }} + - - ₹{{ number_format($c->orders->sum('ttl_amount'), 2) }} - - - - ₹{{ number_format($totalPayable, 2) }} - - - @if($remainingAmount > 0) - - ₹{{ number_format($remainingAmount, 2) }} + + + ₹{{ number_format($orderTotal, 2) }} - @else - - ₹0.00 + + + ₹{{ number_format($totalPayable, 2) }} - @endif - + @if($remainingAmount > 0) + + ₹{{ number_format($remainingAmount, 2) }} + + @else + + ₹0.00 + + @endif + + {{ $c->created_at ? $c->created_at->format('d-m-Y') : '-' }} + + @if($c->status === 'active') + Active + @else + Inactive + @endif + - {{ $c->created_at ? $c->created_at->format('d-m-Y') : '-' }} - +
+ + + - -
- @if($c->status === 'active') - Active - @else - Inactive - @endif - -
- - - - -
- @csrf - -
-
-
+ No customers found.
- - - - - - - - - - - - - - + + + + + + {{-- NEW --}} + + + + + + + + + - - @php - $totalInvoices = $invoices->count(); - $sortedInvoices = $invoices->sortByDesc('created_at'); // Latest first - @endphp - - @forelse($sortedInvoices as $i => $invoice) - - + + @php + $totalInvoices = $invoices->count(); + $sortedInvoices = $invoices->sortByDesc('created_at'); // Latest first + @endphp + + @forelse($sortedInvoices as $i => $invoice) + + - + - + - - - + {{-- NEW: Container column --}} + - + - - + + + + + + + + + + + + + @empty + + {{-- 1 new column वाढवलाय म्हणून colspan 11 --}} + + + @endforelse + - - - @empty - - - - @endforelse -
#Invoice NumberCustomerFinal AmountGST %Total w/GSTStatusInvoice DateDue DateAction
#Invoice NumberCustomerContainerFinal AmountGST %Total w/GSTStatusInvoice DateDue DateAction
{{ $totalInvoices - $i }}
{{ $totalInvoices - $i }} - - + + {{ $invoice->customer_name }} + {{ $invoice->customer_name }} + ₹{{ number_format($invoice->final_amount, 2) }}{{ $invoice->gst_percent }}%₹{{ number_format($invoice->final_amount_with_gst, 2) }} + @if($invoice->container) + {{ $invoice->container->container_number }} + {{-- जर फक्त ID हवी असेल तर: + #{{ $invoice->container->id }} + --}} + @else + — + @endif + - - @if($invoice->status == 'paid') - - @elseif($invoice->status == 'pending') - - @elseif($invoice->status == 'overdue') - - @endif - {{ ucfirst($invoice->status) }} - - + ₹{{ number_format($invoice->final_amount, 2) }} + {{ $invoice->invoice_date }}{{ $invoice->due_date }} + {{ $invoice->gst_percent }}% + + ₹{{ number_format($invoice->final_amount_with_gst, 2) }} + + + @if($invoice->status == 'paid') + + @elseif($invoice->status == 'pending') + + @elseif($invoice->status == 'overdue') + + @endif + {{ ucfirst($invoice->status) }} + + + {{ $invoice->invoice_date }} + + {{ $invoice->due_date }} + + + Entry + +
No invoices found
- - Entry - -
No invoices found
@@ -1366,7 +1426,6 @@
- @endsection \ No newline at end of file diff --git a/resources/views/admin/invoice_edit.blade.php b/resources/views/admin/invoice_edit.blade.php index 475fb79..be6ac79 100644 --- a/resources/views/admin/invoice_edit.blade.php +++ b/resources/views/admin/invoice_edit.blade.php @@ -1,7 +1,9 @@ @extends('admin.layouts.app') + @section('page-title', 'Edit Invoice') + @section('content')
@@ -504,7 +545,6 @@ Invoices Management
- {{-- Stats Cards based on invoices --}}
@php $totalInvoices = $invoices->count(); @@ -512,22 +552,45 @@ $pendingInvoices = $invoices->where('invoice_status', 'pending')->count(); $overdueInvoices = $invoices->where('invoice_status', 'overdue')->count(); @endphp - +
-
{{ $totalInvoices }}
-
Total Invoices
+
+ +
+
+
{{ $totalInvoices }}
+
Total Invoices
+
+ +
-
{{ $pendingInvoices }}
-
Pending Invoices
+
+ +
+
+
{{ $pendingInvoices }}
+
Pending Invoices
+
+
-
{{ $overdueInvoices }}
-
Overdue Invoices
+
+ +
+
+
{{ $overdueInvoices }}
+
Overdue Invoices
+
@@ -570,7 +633,7 @@ Invoice No Invoice Date - Mark No + {{-- Mark No --}} Container No Container Date Company @@ -586,10 +649,30 @@ $status = strtolower($inv->invoice_status ?? 'pending'); @endphp - {{ $inv->invoice_number }} + + @if($inv->invoice_number) +
+ {{ $inv->invoice_number }} + + @else + - + @endif + {{ $inv->invoice_date ? \Carbon\Carbon::parse($inv->invoice_date)->format('d-m-Y') : '-' }} - {{ $inv->mark_no ?? '-' }} - {{ $inv->container_number ?? '-' }} + {{-- {{ $inv->mark_no ?? '-' }} --}} + + @if(!empty($inv->container_id) && !empty($inv->container_number)) + + {{ $inv->container_number }} + + @else + - + @endif + {{ $inv->container_date ? \Carbon\Carbon::parse($inv->container_date)->format('d-m-Y') : '-' }} {{ $inv->company_name ?? '-' }} {{ $inv->customer_name ?? '-' }} @@ -633,6 +716,20 @@ @endif
+ + + + + \ No newline at end of file diff --git a/resources/views/admin/reports.blade.php b/resources/views/admin/reports.blade.php index fd2c09a..8f0121d 100644 --- a/resources/views/admin/reports.blade.php +++ b/resources/views/admin/reports.blade.php @@ -577,7 +577,7 @@ Container Date Company Name Customer Name - Mark No + {{-- Mark No --}} Invoice No Invoice Date Invoice Amount @@ -609,11 +609,11 @@ {{ $r->customer_name ?? '-' }} - + {{-- {{ $r->mark_no ?? '-' }} - + --}} {{ $r->invoice_number }} @@ -640,7 +640,7 @@ @empty - +
@@ -799,7 +799,7 @@ if (filteredReports.length === 0) { tbody.innerHTML = ` - +
@@ -842,11 +842,11 @@ ${report.customer_name || '-'} - + ${report.invoice_number || '-'} diff --git a/resources/views/admin/requests.blade.php b/resources/views/admin/requests.blade.php index c175b61..dc75442 100644 --- a/resources/views/admin/requests.blade.php +++ b/resources/views/admin/requests.blade.php @@ -15,11 +15,19 @@ @endphp
-

User Requests (Total: {{ $total }})

+

User Requests (Total: {{ $total }})

- @can('request.update_profile') - - - Profile Update Requests - - @if($pendingProfileUpdates > 0) - - {{ $pendingProfileUpdates }} - - @endif - - @endcan -
+ @can('request.update_profile') + + + Profile Update Requests + @if($pendingProfileUpdates > 0) + + {{ $pendingProfileUpdates }} + + @endif + + @endcan +
-
@@ -375,7 +388,7 @@ a.btn.btn-primary.position-relative .badge {
- +
{{ $requests->where('status', 'pending')->count() }} Pending {{ $requests->where('status', 'approved')->count() }} Approved @@ -385,9 +398,21 @@ a.btn.btn-primary.position-relative .badge {
- - - + + + + + + + + + + + + + + + @forelse($currentItems as $index => $req) @@ -399,33 +424,41 @@ a.btn.btn-primary.position-relative .badge { - @empty @@ -504,4 +537,4 @@ a.btn.btn-primary.position-relative .badge { -@endsection \ No newline at end of file +@endsection diff --git a/resources/views/admin/staff/create.blade.php b/resources/views/admin/staff/create.blade.php index b5d81bb..097e7e3 100644 --- a/resources/views/admin/staff/create.blade.php +++ b/resources/views/admin/staff/create.blade.php @@ -4,6 +4,12 @@ @section('content')
- @if(session('success'))
{{ session('success') }} @@ -716,7 +675,7 @@ document.addEventListener('DOMContentLoaded', function() { // Search filter if (searchTerm) { - const matchesSearch = + const matchesSearch = staff.name.toLowerCase().includes(searchTerm) || staff.email.toLowerCase().includes(searchTerm) || (staff.employee_id && staff.employee_id.toLowerCase().includes(searchTerm)) || @@ -893,4 +852,4 @@ function renderTable() { }); } -@endsection \ No newline at end of file +@endsection diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index 3cab29d..473a0f4 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -1,36 +0,0 @@ - diff --git a/routes/web.php b/routes/web.php index 865c97b..79d6d8e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -15,7 +15,6 @@ use App\Http\Controllers\Admin\AdminChatController; use Illuminate\Support\Facades\Broadcast; use App\Http\Controllers\ContainerController; - // --------------------------- // Public Front Page // --------------------------- @@ -31,9 +30,9 @@ Broadcast::routes(['middleware' => ['web']]); Route::post('/broadcasting/auth', function (\Illuminate\Http\Request $request) { \Log::info('🎯 Broadcasting Auth Request', [ - 'channel' => $request->input('channel_name'), - 'admin_check'=> auth('admin')->check(), - 'web_check' => auth('web')->check(), + 'channel' => $request->input('channel_name'), + 'admin_check' => auth('admin')->check(), + 'web_check' => auth('web')->check(), ]); if (auth('admin')->check()) { @@ -50,7 +49,6 @@ Route::post('/broadcasting/auth', function (\Illuminate\Http\Request $request) { return response()->json(['message' => 'Unauthenticated'], 403); })->middleware('web'); - // --------------------------- // ADMIN LOGIN ROUTES // --------------------------- @@ -62,7 +60,6 @@ Route::prefix('admin')->group(function () { Broadcast::routes(['middleware' => ['web']]); - // ========================================== // PROTECTED ADMIN ROUTES (session protected) // ========================================== @@ -93,37 +90,35 @@ Route::prefix('admin') [\App\Http\Controllers\Admin\AdminOrderController::class, 'uploadExcelPreview'] )->name('admin.orders.upload.excel.preview'); - - //--------------------------- - // CONTAINER ROUTES - //--------------------------- - // Index + list //--------------------------- // CONTAINER ROUTES //--------------------------- Route::get('/containers', [ContainerController::class, 'index']) ->name('containers.index'); - + Route::get('/containers/create', [ContainerController::class, 'create']) ->name('containers.create'); - + Route::post('/containers', [ContainerController::class, 'store']) ->name('containers.store'); - + Route::get('/containers/{container}', [ContainerController::class, 'show']) ->name('containers.show'); - + Route::post('/containers/{container}/update-rows', [ContainerController::class, 'updateRows']) ->name('containers.rows.update'); - + Route::post('containers/{container}/status', [ContainerController::class, 'updateStatus']) ->name('containers.update-status'); - + Route::delete('/containers/{container}', [ContainerController::class, 'destroy']) ->name('containers.destroy'); + Route::get('containers/{container}/download-pdf', [ContainerController::class, 'downloadPdf']) + ->name('containers.download.pdf'); + + Route::get('/admin/containers/{container}/download-excel', [ContainerController::class, 'downloadExcel']) + ->name('containers.download.excel'); - - // --------------------------- // USER REQUESTS // --------------------------- @@ -149,7 +144,6 @@ Route::prefix('admin') [UserRequestController::class, 'rejectProfileUpdate'] )->name('admin.profile.reject'); - // --------------------------- // MARK LIST // --------------------------- @@ -159,19 +153,15 @@ Route::prefix('admin') Route::get('/mark-list/status/{id}', [AdminMarkListController::class, 'toggleStatus']) ->name('admin.marklist.toggle'); - // --------------------------- // ORDERS (UPDATED) // --------------------------- - // मुख्य Orders पेज (invoice + container listing) Route::get('/orders', [AdminOrderController::class, 'index']) ->name('admin.orders'); - // जुनं list route (असल्या वापरासाठी पण index ला point) Route::get('/orders/list', [AdminOrderController::class, 'index']) ->name('admin.orders.index'); - // Order show (old single order view) Route::get('/orders/{id}', [AdminOrderController::class, 'show']) ->name('admin.orders.show'); @@ -193,7 +183,6 @@ Route::prefix('admin') Route::get('/orders/{id}/see', [AdminOrderController::class, 'see']) ->name('orders.see'); - // --------------------------- // ORDERS (FIXED ROUTES) // --------------------------- @@ -212,7 +201,6 @@ Route::prefix('admin') Route::delete('/orders/{id}/delete', [AdminOrderController::class, 'destroy']) ->name('admin.orders.destroy'); - // --------------------------- // SHIPMENTS (FIXED ROUTES) // --------------------------- @@ -240,7 +228,6 @@ Route::prefix('admin') Route::get('/shipment/dummy/{id}', [ShipmentController::class, 'dummy']) ->name('admin.shipments.dummy'); - // --------------------------- // INVOICES // --------------------------- @@ -271,9 +258,10 @@ Route::prefix('admin') Route::post('/admin/invoices/{invoice}/charge-group', [AdminInvoiceController::class, 'storeChargeGroup']) ->name('admin.invoices.charge-group.store'); - Route::get('/admin/invoices/create', [InvoiceController::class, 'create']) - ->name('admin.invoices.create'); - + // जर create page वापरायचा असेल तर AdminInvoiceController मध्ये create() असावा. + // नसेल तर हा route comment / delete कर. + // Route::get('/admin/invoices/create', [AdminInvoiceController::class, 'create']) + // ->name('admin.invoices.create'); // --------------------------- // CUSTOMERS @@ -293,7 +281,6 @@ Route::prefix('admin') Route::post('/customers/{id}/status', [AdminCustomerController::class, 'toggleStatus']) ->name('admin.customers.status'); - // CHAT Route::get('/chat-support', [AdminChatController::class, 'index']) ->name('admin.chat_support'); @@ -305,7 +292,6 @@ Route::prefix('admin') ->name('admin.chat.send'); }); - // ========================================== // ADMIN ACCOUNT (AJAX) ROUTES // ========================================== @@ -351,7 +337,6 @@ Route::prefix('admin/account') ->name('remove.order.from.entry'); }); - // --------------------------- // REPORTS DOWNLOAD ROUTES // --------------------------- @@ -373,7 +358,7 @@ Route::middleware(['auth:admin']) Route::resource('staff', AdminStaffController::class); }); -// Extra admin prefix group (तसाच ठेवला) +// Extra admin prefix group Route::prefix('admin')->middleware('auth:admin')->group(function () { // ... your routes }); @@ -382,6 +367,14 @@ Route::post('/admin/broadcasting/auth', function () { return Broadcast::auth(request()); })->middleware('auth:admin'); -Route::get('/admin/invoices/{invoice}/download', [InvoiceController::class, 'download']) +// INVOICE DOWNLOAD (AdminInvoiceController वापरून) +Route::get('/admin/invoices/{invoice}/download', [AdminInvoiceController::class, 'download']) ->name('admin.invoices.download'); + + +// CONTAINER POPUP VIEW +// In admin group +Route::get('/admin/containers/{container}/popup', [\App\Http\Controllers\ContainerController::class, 'popupPopup']) + ->name('containers.popup'); + \ No newline at end of file
#Request IDNameCompanyEmailMobileAddressPriorityDateStatusActions
#Request IDNameCompanyEmailMobileAddressPriorityDateStatusActions
{{ $req->mobile_no }} {{ Str::limit($req->address, 30) }} - @if(strtolower($req->priority) == 'high')High - @elseif(strtolower($req->priority) == 'medium')Medium - @elseif(strtolower($req->priority) == 'low')Low - @else{{ $req->priority ?? 'N/A' }}@endif + @if(strtolower($req->priority) == 'high') + High + @elseif(strtolower($req->priority) == 'medium') + Medium + @elseif(strtolower($req->priority) == 'low') + Low + @else + {{ $req->priority ?? 'N/A' }} + @endif {{ $req->date }} - @if($req->status == 'approved')Approved - @elseif($req->status == 'rejected')Rejected - @elsePending@endif + @if($req->status == 'approved') + Approved + @elseif($req->status == 'rejected') + Rejected + @else + Pending + @endif @if($req->status == 'pending') - + Approve - + Reject @else No Action @endif
No records found.