diff --git a/app/Http/Controllers/Admin/AdminAuthController.php b/app/Http/Controllers/Admin/AdminAuthController.php index 3b664d9..b7232e0 100644 --- a/app/Http/Controllers/Admin/AdminAuthController.php +++ b/app/Http/Controllers/Admin/AdminAuthController.php @@ -5,6 +5,10 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; +use App\Models\Container; +use App\Models\Invoice; +use App\Models\User; +use App\Models\MarkList; class AdminAuthController extends Controller { @@ -31,16 +35,15 @@ class AdminAuthController extends Controller } $credentials = [ - $field => $loginInput, + $field => $loginInput, 'password' => $request->password, ]; - // attempt login if (Auth::guard('admin')->attempt($credentials)) { $request->session()->regenerate(); $user = Auth::guard('admin')->user(); - - return redirect()->route('admin.dashboard')->with('success', 'Welcome back, ' . $user->name . '!'); + return redirect()->route('admin.dashboard') + ->with('success', 'Welcome back, ' . $user->name . '!'); } return back()->withErrors(['login' => 'Invalid login credentials.']); @@ -51,6 +54,25 @@ class AdminAuthController extends Controller Auth::guard('admin')->logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); - return redirect()->route('admin.login')->with('success', 'Logged out successfully.'); + return redirect()->route('admin.login') + ->with('success', 'Logged out successfully.'); } -} + + public function profile() + { + $user = Auth::guard('admin')->user(); + + // ── Real Stats ── + $stats = [ + 'total_containers' => Container::count(), + 'total_invoices' => Invoice::count(), + 'paid_invoices' => Invoice::where('status', 'paid')->count(), + 'pending_invoices' => Invoice::where('status', 'pending')->count(), + 'total_customers' => User::count(), + 'total_marklist' => MarkList::count(), + 'active_marklist' => MarkList::where('status', 'active')->count(), + ]; + + return view('admin.profile', compact('user', 'stats')); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Admin/AdminInvoiceController.php b/app/Http/Controllers/Admin/AdminInvoiceController.php index 9a14f97..2ba9d72 100644 --- a/app/Http/Controllers/Admin/AdminInvoiceController.php +++ b/app/Http/Controllers/Admin/AdminInvoiceController.php @@ -269,9 +269,23 @@ class AdminInvoiceController extends Controller $newPaid = $paidTotal + $request->amount; $remaining = max(0, $grandTotal - $newPaid); - if ($newPaid >= $grandTotal && $grandTotal > 0) { - $invoice->update(['status' => 'paid']); - } + + + // 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, + ]); return response()->json([ 'status' => 'success', diff --git a/app/Http/Controllers/Admin/AdminOrderController.php b/app/Http/Controllers/Admin/AdminOrderController.php index 91acdf2..eda2d00 100644 --- a/app/Http/Controllers/Admin/AdminOrderController.php +++ b/app/Http/Controllers/Admin/AdminOrderController.php @@ -28,11 +28,23 @@ class AdminOrderController extends Controller * ---------------------------*/ public function dashboard() { - $totalOrders = Order::count(); - $pendingOrders = Order::where('status', 'pending')->count(); - $totalShipments = Shipment::count(); - $totalItems = OrderItem::count(); + // ── Order counts (from Invoice Management / Orders table) ── + $totalOrders = Order::count(); + + // "Pending" म्हणजे delivered नसलेले सर्व orders + // Order तयार होतो तेव्हा status = 'order_placed' असतो, 'pending' नाही + $deliveredStatuses = ['delivered']; + $pendingOrders = Order::whereNotIn('status', $deliveredStatuses)->count(); + + // ── Invoice counts ── + $totalContainers = Container::count(); + $totalInvoices = Invoice::count(); + $paidInvoices = Invoice::where('status', 'paid')->count(); + $pendingInvoices = Invoice::where('status', 'pending')->count(); + $overdueInvoices = Invoice::where('status', 'overdue')->count(); $totalRevenue = Invoice::sum('final_amount_with_gst'); + + // ── User / Staff counts ── $activeCustomers = User::where('status', 'active')->count(); $inactiveCustomers = User::where('status', 'inactive')->count(); $totalStaff = Admin::where('type', 'staff')->count(); @@ -43,8 +55,11 @@ class AdminOrderController extends Controller return view('admin.dashboard', compact( 'totalOrders', 'pendingOrders', - 'totalShipments', - 'totalItems', + 'totalContainers', + 'totalInvoices', + 'paidInvoices', + 'pendingInvoices', + 'overdueInvoices', 'totalRevenue', 'activeCustomers', 'inactiveCustomers', @@ -90,11 +105,23 @@ class AdminOrderController extends Controller ->when($request->filled('status'), function ($q) use ($request) { $q->where('invoices.status', $request->status); }) - ->orderByDesc('invoices.invoice_date') // इथे बदल - ->orderByDesc('invoices.id') // same-date साठी tie-breaker + ->orderByDesc('invoices.invoice_date') + ->orderByDesc('invoices.id') ->get(); - - return view('admin.orders', compact('invoices')); + + // ── Real DB counts (filter-independent) ── + $totalInvoices = \App\Models\Invoice::count(); + $paidInvoices = \App\Models\Invoice::where('status', 'paid')->count(); + $pendingInvoices = \App\Models\Invoice::where('status', 'pending')->count(); + $overdueInvoices = \App\Models\Invoice::where('status', 'overdue')->count(); + + return view('admin.orders', compact( + 'invoices', + 'totalInvoices', + 'paidInvoices', + 'pendingInvoices', + 'overdueInvoices' + )); } /* --------------------------- @@ -759,4 +786,4 @@ class AdminOrderController extends Controller ], 500); } } -} +} \ No newline at end of file diff --git a/app/Http/Controllers/ContainerController.php b/app/Http/Controllers/ContainerController.php index 3359286..94ac571 100644 --- a/app/Http/Controllers/ContainerController.php +++ b/app/Http/Controllers/ContainerController.php @@ -193,6 +193,7 @@ class ContainerController extends Controller 'kg_col' => null, 'totalkg_col' => null, 'itemno_col' => null, + 'shopno_col' => null, ]; foreach ($header as $colIndex => $headingText) { @@ -233,6 +234,11 @@ class ContainerController extends Controller strpos($normalized, 'ITEM') !== false ) { $essentialColumns['itemno_col'] = $colIndex; + } elseif ( + strpos($normalized, 'SHOPNO') !== false || + strpos($normalized, 'SHOP') !== false + ) { + $essentialColumns['shopno_col'] = $colIndex; } } @@ -395,8 +401,8 @@ class ContainerController extends Controller if (!empty($unmatchedMarks)) { foreach ($cleanedRows as $item) { - $row = $item['row']; - $offset = $item['offset']; + $row = $item['row']; + $offset = $item['offset']; $rowMark = trim((string)($row[$essentialColumns['itemno_col']] ?? '')); if ($rowMark === '' || !in_array($rowMark, $unmatchedMarks)) { @@ -518,32 +524,27 @@ class ContainerController extends Controller $firstMark = $rowsForCustomer[0]['mark']; $snap = $markToSnapshot[$firstMark] ?? null; - // ✅ Customer User model वरून fetch करा (customer_id string आहे जसे CID-2025-000001) $customerUser = \App\Models\User::where('customer_id', $customerId)->first(); $invoice = new Invoice(); $invoice->container_id = $container->id; - $invoice->customer_id = $customerUser->id ?? null; // ✅ integer id store करतोय + $invoice->customer_id = $customerUser->id ?? null; $invoice->mark_no = $firstMark; $invoice->invoice_number = $this->generateInvoiceNumber(); - // 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'); - // ✅ Snapshot data from MarkList (backward compatibility) if ($snap) { $invoice->customer_name = $snap['customer_name'] ?? null; $invoice->company_name = $snap['company_name'] ?? null; $invoice->customer_mobile = $snap['mobile_no'] ?? null; } - // ✅ User model वरून email, address, pincode घ्या if ($customerUser) { $invoice->customer_email = $customerUser->email ?? null; $invoice->customer_address = $customerUser->address ?? null; @@ -569,6 +570,7 @@ class ContainerController extends Controller foreach ($rowsForCustomer as $item) { $row = $item['row']; $offset = $item['offset']; + $mark = $item['mark']; // ✅ mark_no from Excel $description = $essentialColumns['desc_col'] !== null ? ($row[$essentialColumns['desc_col']] ?? null) : null; $ctn = $essentialColumns['ctn_col'] !== null ? (int) ($row[$essentialColumns['ctn_col']] ?? 0) : 0; @@ -582,6 +584,8 @@ class ContainerController extends Controller $kg = $essentialColumns['kg_col'] !== null ? (float) ($row[$essentialColumns['kg_col']] ?? 0) : 0; $ttlKg = $essentialColumns['totalkg_col'] !== null ? (float) ($row[$essentialColumns['totalkg_col']] ?? $kg) : $kg; + $shopNo = $essentialColumns['shopno_col'] !== null ? ($row[$essentialColumns['shopno_col']] ?? null) : null; + $rowIndex = $headerRowIndex + 1 + $offset; InvoiceItem::create([ @@ -599,7 +603,8 @@ class ContainerController extends Controller 'ttl_cbm' => $ttlCbm, 'kg' => $kg, 'ttl_kg' => $ttlKg, - 'shop_no' => null, + 'shop_no' => $shopNo, + 'mark_no' => $mark, // ✅ save mark_no from Excel ]); $totalAmount += $ttlAmount; @@ -620,8 +625,7 @@ class ContainerController extends Controller public function show(Container $container) { $container->load('rows'); - - // paid / paying invoices च्या row indexes collect करा + $lockedRowIndexes = \App\Models\Invoice::whereIn('invoices.status', ['paid', 'paying']) ->where('invoices.container_id', $container->id) ->join('invoice_items', 'invoices.id', '=', 'invoice_items.invoice_id') @@ -630,7 +634,7 @@ class ContainerController extends Controller ->unique() ->values() ->toArray(); - + return view('admin.container_show', compact('container', 'lockedRowIndexes')); } @@ -647,14 +651,12 @@ class ContainerController extends Controller continue; } - // 1) update container_rows.data $data = $row->data ?? []; foreach ($cols as $colHeader => $value) { $data[$colHeader] = $value; } $row->update(['data' => $data]); - // 2) normalize keys $normalizedMap = []; foreach ($data as $key => $value) { if ($key === null || $key === '') { @@ -666,7 +668,6 @@ class ContainerController extends Controller $normalizedMap[$normKey] = $value; } - // helper: get first numeric value from given keys $getFirstNumeric = function (array $map, array $possibleKeys) { foreach ($possibleKeys as $search) { $normSearch = strtoupper($search); @@ -686,23 +687,19 @@ class ContainerController extends Controller 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 + $qtyKeys = ['QTY', 'PCS', 'PIECES']; + $ttlQtyKeys = ['ITLQTY', 'TOTALQTY', 'TTLQTY']; $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; } @@ -725,7 +722,6 @@ class ContainerController extends Controller $amount = $price * $ttlQ; } - // 4) get description $desc = null; foreach (['DESCRIPTION', 'DESC'] as $dKey) { $normD = str_replace([' ', '/', '-', '.'], '', strtoupper($dKey)); @@ -737,9 +733,31 @@ class ContainerController extends Controller } } + $shopNo = null; + foreach (['SHOPNO', 'SHOP'] as $sKey) { + $normS = str_replace([' ', '/', '-', '.'], '', strtoupper($sKey)); + foreach ($normalizedMap as $nKey => $v) { + if (strpos($nKey, $normS) !== false) { + $shopNo = is_string($v) ? trim($v) : $v; + break 2; + } + } + } + + // ✅ Get mark_no + $markNo = null; + foreach (['MARKNO', 'MARK', 'ITEMNO', 'ITEM'] as $mKey) { + $normM = str_replace([' ', '/', '-', '.'], '', strtoupper($mKey)); + foreach ($normalizedMap as $nKey => $v) { + if (strpos($nKey, $normM) !== false) { + $markNo = is_string($v) ? trim($v) : $v; + break 2; + } + } + } + $rowIndex = $row->row_index; - // 5) find linked invoice_items $items = InvoiceItem::where('container_id', $container->id) ->where('container_row_index', $rowIndex) ->get(); @@ -751,18 +769,19 @@ class ContainerController extends Controller ->get(); } - // 6) update invoice_items + recalc invoice totals foreach ($items as $item) { $item->description = $desc; $item->ctn = $ctn; - $item->qty = $qty; // per carton - $item->ttl_qty = $ttlQ; // total + $item->qty = $qty; + $item->ttl_qty = $ttlQ; $item->price = $price; $item->ttl_amount = $amount; $item->cbm = $cbm; $item->ttl_cbm = $ttlC; $item->kg = $kg; $item->ttl_kg = $ttlK; + $item->shop_no = $shopNo; + $item->mark_no = $markNo; // ✅ update mark_no $item->save(); $invoice = $item->invoice; @@ -877,7 +896,6 @@ class ContainerController extends Controller abort(404, 'Excel file not found on record.'); } - // Stored path like "containers/abc.xlsx" $path = $container->excel_file; if (!Storage::exists($path)) { @@ -891,10 +909,8 @@ class ContainerController extends Controller public function popupPopup(Container $container) { - // existing show सारखाच data वापरू $container->load('rows'); - // summary आधीपासून index() मध्ये जसा काढतोस तसाच logic reuse $rows = $container->rows ?? collect(); $totalCtn = 0; diff --git a/app/Models/InvoiceItem.php b/app/Models/InvoiceItem.php index ee1f41e..35c7623 100644 --- a/app/Models/InvoiceItem.php +++ b/app/Models/InvoiceItem.php @@ -29,6 +29,7 @@ class InvoiceItem extends Model 'ttl_kg', 'shop_no', + 'mark_no', ]; /**************************** diff --git a/database/migrations/2026_03_13_120013_add_mark_no_to_invoice_items_table.php b/database/migrations/2026_03_13_120013_add_mark_no_to_invoice_items_table.php new file mode 100644 index 0000000..5cf174e --- /dev/null +++ b/database/migrations/2026_03_13_120013_add_mark_no_to_invoice_items_table.php @@ -0,0 +1,27 @@ +string('mark_no')->nullable(); // after() काहीही नको + }); + } + + public function down() + { + Schema::table('invoice_items', function (Blueprint $table) { + $table->dropColumn('mark_no'); + }); + } + + +}; diff --git a/public/invoices/invoice-INV-2026-000222.pdf b/public/invoices/invoice-INV-2026-000222.pdf new file mode 100644 index 0000000..8338a8c Binary files /dev/null and b/public/invoices/invoice-INV-2026-000222.pdf differ diff --git a/public/invoices/invoice-INV-2026-000225.pdf b/public/invoices/invoice-INV-2026-000225.pdf new file mode 100644 index 0000000..dc98e19 Binary files /dev/null and b/public/invoices/invoice-INV-2026-000225.pdf differ diff --git a/resources/views/admin/container_show.blade.php b/resources/views/admin/container_show.blade.php index a43a80e..2e7b39b 100644 --- a/resources/views/admin/container_show.blade.php +++ b/resources/views/admin/container_show.blade.php @@ -40,6 +40,73 @@ margin-top: 2px; } + /* DOWNLOAD BUTTONS - NEW STYLES */ + .cm-download-pdf { + background: linear-gradient(100deg, #4c6fff 0%, #8e54e9 100%) !important; + color: #fff !important; + border: none !important; + font-weight: 600 !important; + font-size: 12.5px !important; + padding: 8px 16px !important; + border-radius: 8px !important; + box-shadow: 0 4px 14px rgba(76,111,255,0.4) !important; + transition: all 0.2s ease !important; + text-decoration: none !important; + display: inline-flex !important; + align-items: center !important; + gap: 6px !important; + } + .cm-download-pdf:hover { + transform: translateY(-1px) !important; + box-shadow: 0 6px 20px rgba(76,111,255,0.5) !important; + color: #fff !important; + opacity: 0.95 !important; + } + + .cm-download-excel { + background: linear-gradient(100deg, #10b981 0%, #059669 100%) !important; + color: #fff !important; + border: none !important; + font-weight: 600 !important; + font-size: 12.5px !important; + padding: 8px 16px !important; + border-radius: 8px !important; + box-shadow: 0 4px 14px rgba(16,185,129,0.4) !important; + transition: all 0.2s ease !important; + text-decoration: none !important; + display: inline-flex !important; + align-items: center !important; + gap: 6px !important; + } + .cm-download-excel:hover { + transform: translateY(-1px) !important; + box-shadow: 0 6px 20px rgba(16,185,129,0.5) !important; + color: #fff !important; + opacity: 0.95 !important; + } + + .cm-back-btn { + background: linear-gradient(100deg, #6b7280 0%, #4b5563 100%) !important; + color: #fff !important; + border: none !important; + font-weight: 600 !important; + font-size: 12.5px !important; + padding: 8px 16px !important; + border-radius: 8px !important; + box-shadow: 0 4px 14px rgba(107,114,128,0.4) !important; + transition: all 0.2s ease !important; + text-decoration: none !important; + display: inline-flex !important; + align-items: center !important; + gap: 6px !important; + } + .cm-back-btn:hover { + transform: translateY(-1px) !important; + box-shadow: 0 6px 20px rgba(107,114,128,0.5) !important; + color: #fff !important; + opacity: 0.95 !important; + } + .cm-main-card { border-radius: 14px; border: none; @@ -65,7 +132,7 @@ .cm-info-cards-row { display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); /* 3 cards one row */ + grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; padding: 14px 18px 8px 18px; } @@ -132,7 +199,6 @@ color: #fff7ed; } - /* TOTAL BOXES */ .cm-total-cards-row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); @@ -421,6 +487,11 @@ grid-template-columns: 1fr; } } + + .cm-table-scroll-outer { + margin: 10px 14px 30px 14px; /* फक्त हे बदल करा */ +} +