diff --git a/app/Http/Controllers/Admin/AdminInvoiceController.php b/app/Http/Controllers/Admin/AdminInvoiceController.php index 0209ff0..19d313e 100644 --- a/app/Http/Controllers/Admin/AdminInvoiceController.php +++ b/app/Http/Controllers/Admin/AdminInvoiceController.php @@ -26,15 +26,13 @@ class AdminInvoiceController extends Controller // ------------------------------------------------------------- public function popup($id) { - $invoice = Invoice::with(['items', 'order'])->findOrFail($id); + $invoice = Invoice::with(['items', 'order', 'installments'])->findOrFail($id); - // Find actual Shipment record - $shipment = \App\Models\Shipment::whereHas('items', function ($q) use ($invoice) { - $q->where('order_id', $invoice->order_id); - }) - ->first(); + $shipment = \App\Models\Shipment::whereHas('items', function ($q) use ($invoice) { + $q->where('order_id', $invoice->order_id); + })->first(); - return view('admin.popup_invoice', compact('invoice', 'shipment')); + return view('admin.popup_invoice', compact('invoice', 'shipment')); } // ------------------------------------------------------------- @@ -145,6 +143,22 @@ class AdminInvoiceController extends Controller $invoice->update(['pdf_path' => 'invoices/' . $fileName]); } + public function downloadInvoice($id) +{ + $invoice = Invoice::findOrFail($id); + + // Generate PDF if missing + if ( + !$invoice->pdf_path || + !file_exists(public_path($invoice->pdf_path)) + ) { + $this->generateInvoicePDF($invoice); + $invoice->refresh(); + } + + return response()->download(public_path($invoice->pdf_path)); +} + // ------------------------------------------------------------- // INSTALLMENTS (ADD/DELETE) // ------------------------------------------------------------- diff --git a/app/Http/Controllers/Admin/AdminOrderController.php b/app/Http/Controllers/Admin/AdminOrderController.php index 486040f..f116b96 100644 --- a/app/Http/Controllers/Admin/AdminOrderController.php +++ b/app/Http/Controllers/Admin/AdminOrderController.php @@ -13,6 +13,11 @@ use App\Models\User; use PDF; use Maatwebsite\Excel\Facades\Excel; use App\Exports\OrdersExport; +use App\Imports\OrderItemsPreviewImport; + + +use Illuminate\Validation\ValidationException; + class AdminOrderController extends Controller { @@ -36,44 +41,6 @@ class AdminOrderController extends Controller return view('admin.orders_create', compact('markList')); } - public function store(Request $request) - { - $data = $request->validate([ - 'mark_no' => 'required|string', - 'origin' => 'nullable|string', - 'destination' => 'nullable|string', - 'ctn' => 'nullable|numeric', - 'qty' => 'nullable|numeric', - 'ttl_qty' => 'nullable|numeric', - 'ttl_amount' => 'nullable|numeric', - 'cbm' => 'nullable|numeric', - 'ttl_cbm' => 'nullable|numeric', - 'kg' => 'nullable|numeric', - 'ttl_kg' => 'nullable|numeric', - ]); - - $order = Order::create([ - 'order_id' => $this->generateOrderId(), - 'mark_no' => $data['mark_no'], - 'origin' => $data['origin'] ?? null, - 'destination'=> $data['destination'] ?? null, - 'ctn' => $data['ctn'] ?? 0, - 'qty' => $data['qty'] ?? 0, - 'ttl_qty' => $data['ttl_qty'] ?? 0, - 'ttl_amount' => $data['ttl_amount'] ?? 0, - 'cbm' => $data['cbm'] ?? 0, - 'ttl_cbm' => $data['ttl_cbm'] ?? 0, - 'kg' => $data['kg'] ?? 0, - 'ttl_kg' => $data['ttl_kg'] ?? 0, - 'status' => 'pending', - ]); - - $this->createInvoice($order); - - return redirect()->route('admin.orders.show', $order->id) - ->with('success', 'Order created successfully.'); - } - /* --------------------------- * SHOW / POPUP * ---------------------------*/ @@ -580,7 +547,7 @@ class AdminOrderController extends Controller 'ttl_cbm' => $total_ttl_cbm, 'kg' => $total_kg, 'ttl_kg' => $total_ttl_kg, - 'status' => 'pending', + 'status' => 'order_placed', ]); // 6) order items @@ -723,4 +690,36 @@ class AdminOrderController extends Controller ]); } } + + + +public function uploadExcelPreview(Request $request) +{ + try { + $request->validate([ + 'excel' => 'required|file|mimes:xlsx,xls' + ]); + + $import = new OrderItemsPreviewImport(); + Excel::import($import, $request->file('excel')); + + return response()->json([ + 'success' => true, + 'items' => $import->rows + ]); + } catch (ValidationException $e) { + return response()->json([ + 'success' => false, + 'message' => 'Invalid Excel file format' + ], 422); + } catch (\Throwable $e) { + \Log::error($e); + return response()->json([ + 'success' => false, + 'message' => 'Server error' + ], 500); + } +} + + } diff --git a/app/Http/Controllers/Admin/ShipmentController.php b/app/Http/Controllers/Admin/ShipmentController.php index 6feffef..781507e 100644 --- a/app/Http/Controllers/Admin/ShipmentController.php +++ b/app/Http/Controllers/Admin/ShipmentController.php @@ -20,7 +20,11 @@ class ShipmentController extends Controller $usedOrderIds = ShipmentItem::pluck('order_id')->toArray(); // 2) Load available orders (not used in any shipment) - $availableOrders = Order::whereNotIn('id', $usedOrderIds)->get(); + $availableOrders = Order::whereNotIn('id', $usedOrderIds) + ->where('status', '!=', 'order_placed') + ->get(); + + // 3) Load all shipments for listing $shipments = Shipment::latest()->get(); @@ -65,6 +69,16 @@ class ShipmentController extends Controller // CALCULATE TOTALS // ----------------------------- $orders = Order::whereIn('id', $request->order_ids)->get(); + foreach ($orders as $order) { + if ($order->status === 'order_placed') { + return back()->with( + 'error', + "Order {$order->order_id} is not ready for shipment" + ); + } + } + + $total_ctn = $orders->sum('ctn'); $total_qty = $orders->sum('qty'); @@ -82,7 +96,7 @@ class ShipmentController extends Controller 'shipment_id' => $newShipmentId, 'origin' => $request->origin, 'destination' => $request->destination, - 'status' => Shipment::STATUS_PENDING, + 'status' => Shipment::STATUS_SHIPMENT_READY, 'shipment_date' => $request->shipment_date, 'total_ctn' => $total_ctn, @@ -135,29 +149,35 @@ class ShipmentController extends Controller * Update Shipment status from action button */ public function updateStatus(Request $request) - { - $request->validate([ - 'shipment_id' => 'required|exists:shipments,id', - 'status' => 'required|string' - ]); +{ + $request->validate([ + 'shipment_id' => 'required|exists:shipments,id', + 'status' => 'required|string' + ]); - // 1) Update shipment status - $shipment = Shipment::findOrFail($request->shipment_id); - $shipment->status = $request->status; - $shipment->save(); + $shipment = Shipment::findOrFail($request->shipment_id); + $shipment->status = $request->status; + $shipment->save(); - // 2) Update ALL related orders' status - foreach ($shipment->orders as $order) { - $order->status = $shipment->status; // status is string: pending, in_transit, dispatched, delivered - $order->save(); + // ✅ Sync shipment status to orders ONLY after shipment exists + foreach ($shipment->orders as $order) { + + // Prevent rollback or overwrite + if ($order->status === 'delivered') { + continue; } - return redirect()->back()->with( - 'success', - "Shipment status updated to {$shipment->statusLabel()} and related orders updated." - ); + $order->status = $shipment->status; + $order->save(); } + return redirect()->back()->with( + 'success', + "Shipment status updated to {$shipment->statusLabel()}." + ); +} + + /** * Update shipment details */ @@ -266,11 +286,23 @@ public function addOrders(Request $request, Shipment $shipment) 'order_ids' => 'required|array|min:1', ]); - // फक्त न वापरलेले orders घ्या $orders = Order::whereIn('id', $request->order_ids)->get(); foreach ($orders as $order) { - // pivot मध्ये insert + + if ($order->status === 'order_placed') { + return back()->with( + 'error', + "Order {$order->order_id} is not ready for shipment" + ); + } + + + // Prevent duplicates + if (ShipmentItem::where('order_id', $order->id)->exists()) { + continue; + } + ShipmentItem::create([ 'shipment_id' => $shipment->id, 'order_id' => $order->id, @@ -282,23 +314,25 @@ public function addOrders(Request $request, Shipment $shipment) ]); } - // totals + // Recalculate totals $orderIds = ShipmentItem::where('shipment_id', $shipment->id)->pluck('order_id'); $allOrders = Order::whereIn('id', $orderIds)->get(); - $shipment->total_ctn = $allOrders->sum('ctn'); - $shipment->total_qty = $allOrders->sum('qty'); - $shipment->total_ttl_qty = $allOrders->sum('ttl_qty'); - $shipment->total_cbm = $allOrders->sum('cbm'); - $shipment->total_ttl_cbm = $allOrders->sum('ttl_cbm'); - $shipment->total_kg = $allOrders->sum('kg'); - $shipment->total_ttl_kg = $allOrders->sum('ttl_kg'); - $shipment->total_amount = $allOrders->sum('ttl_amount'); - $shipment->save(); + $shipment->update([ + 'total_ctn' => $allOrders->sum('ctn'), + 'total_qty' => $allOrders->sum('qty'), + 'total_ttl_qty' => $allOrders->sum('ttl_qty'), + 'total_cbm' => $allOrders->sum('cbm'), + 'total_ttl_cbm' => $allOrders->sum('ttl_cbm'), + 'total_kg' => $allOrders->sum('kg'), + 'total_ttl_kg' => $allOrders->sum('ttl_kg'), + 'total_amount' => $allOrders->sum('ttl_amount'), + ]); return redirect() ->route('admin.shipments.dummy', $shipment->id) ->with('success', 'Orders added to shipment successfully.'); } + } \ No newline at end of file diff --git a/app/Http/Controllers/user/UserOrderController.php b/app/Http/Controllers/user/UserOrderController.php index d18f7ae..da77e68 100644 --- a/app/Http/Controllers/user/UserOrderController.php +++ b/app/Http/Controllers/user/UserOrderController.php @@ -289,6 +289,44 @@ public function invoiceDetails($invoice_id) ]); } +public function confirmOrder($order_id) +{ + $user = JWTAuth::parseToken()->authenticate(); + + if (! $user) { + return response()->json([ + 'success' => false, + 'message' => 'Unauthorized' + ], 401); + } + + $order = $user->orders() + ->where('order_id', $order_id) + ->first(); + + if (! $order) { + return response()->json([ + 'success' => false, + 'message' => 'Order not found' + ], 404); + } + + // 🚫 Only allow confirm from order_placed + if ($order->status !== 'order_placed') { + return response()->json([ + 'success' => false, + 'message' => 'Order cannot be confirmed' + ], 422); + } + + $order->status = 'order_confirmed'; + $order->save(); + + return response()->json([ + 'success' => true, + 'message' => 'Order confirmed successfully' + ]); +} diff --git a/app/Imports/OrderItemsPreviewImport.php b/app/Imports/OrderItemsPreviewImport.php new file mode 100644 index 0000000..0865b6f --- /dev/null +++ b/app/Imports/OrderItemsPreviewImport.php @@ -0,0 +1,26 @@ +first()->map(fn ($h) => strtolower(trim($h)))->toArray(); + + foreach ($collection->skip(1) as $row) { + $item = []; + foreach ($header as $i => $key) { + $item[$key] = $row[$i] ?? null; + } + + if (!empty($item['description'])) { + $this->rows[] = $item; + } + } + } +} diff --git a/app/Models/Order.php b/app/Models/Order.php index 029cf35..9362328 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -64,5 +64,25 @@ class Order extends Model } + const STATUS_LABELS = [ + 'order_placed' => 'Order Placed', + 'order_confirmed' => 'Order Confirmed', + 'supplier_warehouse' => 'Supplier Warehouse', + 'consolidate_warehouse'=> 'Consolidate Warehouse', + 'export_custom' => 'Export Custom', + 'international_transit'=> 'International Transit', + 'arrived_india' => 'Arrived at India', + 'import_custom' => 'Import Custom', + 'warehouse' => 'Warehouse', + 'domestic_distribution'=> 'Domestic Distribution', + 'out_for_delivery' => 'Out for Delivery', + 'delivered' => 'Delivered', + ]; + + public function getStatusLabelAttribute() + { + return self::STATUS_LABELS[$this->status] + ?? ucfirst(str_replace('_', ' ', $this->status)); + } } diff --git a/app/Models/Shipment.php b/app/Models/Shipment.php index 95bb5d5..3c5cacd 100644 --- a/app/Models/Shipment.php +++ b/app/Models/Shipment.php @@ -45,25 +45,6 @@ class Shipment extends Model return $this->belongsToMany(Order::class, 'shipment_items', 'shipment_id', 'order_id'); } - // --------------------------- - // STATUS CONSTANTS - // --------------------------- - - const STATUS_PENDING = 'pending'; - const STATUS_IN_TRANSIT = 'in_transit'; - const STATUS_DISPATCHED = 'dispatched'; - const STATUS_DELIVERED = 'delivered'; - - public static function statusOptions() - { - return [ - self::STATUS_PENDING => 'Pending', - self::STATUS_IN_TRANSIT => 'In Transit', - self::STATUS_DISPATCHED => 'Dispatched', - self::STATUS_DELIVERED => 'Delivered', - ]; - } - // --------------------------- // HELPERS // --------------------------- @@ -73,8 +54,38 @@ class Shipment extends Model return $this->items()->count(); } + // --------------------------- + // STATUS CONSTANTS (LOGISTICS FLOW) + // --------------------------- + const STATUS_SHIPMENT_READY = 'shipment_ready'; + const STATUS_EXPORT_CUSTOM = 'export_custom'; + const STATUS_INTERNATIONAL_TRANSIT= 'international_transit'; + const STATUS_ARRIVED_INDIA = 'arrived_india'; + const STATUS_IMPORT_CUSTOM = 'import_custom'; + const STATUS_WAREHOUSE = 'warehouse'; + const STATUS_DOMESTIC_DISTRIBUTION= 'domestic_distribution'; + const STATUS_OUT_FOR_DELIVERY = 'out_for_delivery'; + const STATUS_DELIVERED = 'delivered'; + + public static function statusOptions() + { + return [ + self::STATUS_SHIPMENT_READY => 'Shipment Ready', + self::STATUS_EXPORT_CUSTOM => 'Export Custom', + self::STATUS_INTERNATIONAL_TRANSIT => 'International Transit', + self::STATUS_ARRIVED_INDIA => 'Arrived at India', + self::STATUS_IMPORT_CUSTOM => 'Import Custom', + self::STATUS_WAREHOUSE => 'Warehouse', + self::STATUS_DOMESTIC_DISTRIBUTION => 'Domestic Distribution', + self::STATUS_OUT_FOR_DELIVERY => 'Out for Delivery', + self::STATUS_DELIVERED => 'Delivered', + ]; + } + public function statusLabel() { - return self::statusOptions()[$this->status] ?? ucfirst($this->status); + return self::statusOptions()[$this->status] + ?? ucfirst(str_replace('_', ' ', $this->status)); } + } diff --git a/public/invoices/invoice-INV-2025-000029.pdf b/public/invoices/invoice-INV-2025-000029.pdf index 212a927..80c41f2 100644 Binary files a/public/invoices/invoice-INV-2025-000029.pdf and b/public/invoices/invoice-INV-2025-000029.pdf differ diff --git a/public/invoices/invoice-INV-2025-000031.pdf b/public/invoices/invoice-INV-2025-000031.pdf new file mode 100644 index 0000000..87950b3 Binary files /dev/null and b/public/invoices/invoice-INV-2025-000031.pdf differ diff --git a/public/invoices/invoice-INV-2025-000032.pdf b/public/invoices/invoice-INV-2025-000032.pdf index 7ffbb92..c681ac0 100644 Binary files a/public/invoices/invoice-INV-2025-000032.pdf and b/public/invoices/invoice-INV-2025-000032.pdf differ diff --git a/public/invoices/invoice-INV-2025-000044.pdf b/public/invoices/invoice-INV-2025-000044.pdf new file mode 100644 index 0000000..63c4fa5 Binary files /dev/null and b/public/invoices/invoice-INV-2025-000044.pdf differ diff --git a/public/invoices/invoice-INV-2025-000046.pdf b/public/invoices/invoice-INV-2025-000046.pdf new file mode 100644 index 0000000..39c5a85 Binary files /dev/null and b/public/invoices/invoice-INV-2025-000046.pdf differ diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php index 3d413e3..02f5a9e 100644 --- a/resources/views/admin/dashboard.blade.php +++ b/resources/views/admin/dashboard.blade.php @@ -1284,6 +1284,7 @@ body, .container-fluid { # Order ID Mark No + Date Origin Destination Total CTN @@ -1295,7 +1296,6 @@ body, .container-fluid { Total KG Total TTL KG Status - Date Actions @@ -1351,10 +1351,75 @@ body, .container-fluid { - -
-
- Showing 1 to 10 of {{ $orders->count() }} entries + {{ $order->mark_no }} + {{ $order->origin }} + {{ $order->destination }} + {{ $order->ctn }} + {{ $order->qty }} + {{ $order->ttl_qty }} + ₹{{ number_format($order->ttl_amount, 2) }} + {{ $order->cbm }} + {{ $order->ttl_cbm }} + {{ $order->kg }} + {{ $order->ttl_kg }} + + @php + // Badge color mapping + $badgeMap = [ + 'order_placed' => 'secondary', + 'order_confirmed' => 'info', + 'supplier_warehouse' => 'warning', + 'consolidate_warehouse' => 'warning', + 'export_custom' => 'primary', + 'international_transit' => 'primary', + 'arrived_india' => 'info', + 'import_custom' => 'info', + 'warehouse' => 'dark', + 'domestic_distribution' => 'primary', + 'out_for_delivery' => 'success', + 'delivered' => 'success', + ]; + + // Icon mapping + $iconMap = [ + 'order_placed' => 'bi-clock-fill', + 'order_confirmed' => 'bi-check-circle', + 'supplier_warehouse' => 'bi-box-seam', + 'consolidate_warehouse' => 'bi-boxes', + 'export_custom' => 'bi-upload', + 'international_transit' => 'bi-truck', + 'arrived_india' => 'bi-geo-alt', + 'import_custom' => 'bi-download', + 'warehouse' => 'bi-building', + 'domestic_distribution' => 'bi-diagram-3', + 'out_for_delivery' => 'bi-truck-flatbed', + 'delivered' => 'bi-check-circle-fill', + ]; + + $badgeClass = $badgeMap[$order->status] ?? 'secondary'; + $iconClass = $iconMap[$order->status] ?? 'bi-info-circle'; + @endphp + + + + {{ $order->status_label }} + + + + {{ $order->created_at->format('d-m-Y') }} + + + View + + + + @empty + + No orders found + + @endforelse + +
+ + + + +
@@ -1951,6 +2023,75 @@ document.addEventListener('DOMContentLoaded', function() { e.target.closest('tr').remove(); reindexRows(); }); + +// ===== EXCEL UPLOAD LOGIC ===== +const uploadExcelBtn = document.getElementById('uploadExcelBtn'); +const excelInput = document.getElementById('excelInput'); + +if (uploadExcelBtn && excelInput) { + + uploadExcelBtn.addEventListener('click', () => excelInput.click()); + + excelInput.addEventListener('change', function () { + const file = this.files[0]; + if (!file) return; + + const formData = new FormData(); + formData.append('excel', file); + formData.append('_token', '{{ csrf_token() }}'); + + fetch('{{ route("admin.orders.upload.excel.preview") }}', { + method: 'POST', + body: formData, + headers: { + 'Accept': 'application/json' + } + }) + .then(async res => { + if (!res.ok) { + const text = await res.text(); + throw new Error(text); + } + return res.json(); + }) + .then(res => { + if (!res.success) { + alert('Invalid Excel file'); + return; + } + populateItemsTable(res.items); + }) + .catch(err => { + console.error(err); + alert('Excel upload failed'); + }); + }); + +} + +function populateItemsTable(items) { + itemsTableBody.innerHTML = ''; + + items.forEach((item, index) => { + addRow(index); + const row = itemsTableBody.children[index]; + + row.querySelector('[data-field="description"]').value = item.description ?? ''; + row.querySelector('[data-field="ctn"]').value = item.ctn ?? ''; + row.querySelector('[data-field="qty"]').value = item.qty ?? ''; + row.querySelector('[data-field="ttl_qty"]').value = item.ttl_qty ?? ''; + row.querySelector('[data-field="unit"]').value = item.unit ?? ''; + row.querySelector('[data-field="price"]').value = item.price ?? ''; + row.querySelector('[data-field="ttl_amount"]').value = item.ttl_amount ?? ''; + row.querySelector('[data-field="cbm"]').value = item.cbm ?? ''; + row.querySelector('[data-field="ttl_cbm"]').value = item.ttl_cbm ?? ''; + row.querySelector('[data-field="kg"]').value = item.kg ?? ''; + row.querySelector('[data-field="ttl_kg"]').value = item.ttl_kg ?? ''; + row.querySelector('[data-field="shop_no"]').value = item.shop_no ?? ''; + }); + + reindexRows(); +} }); diff --git a/resources/views/admin/invoice_edit.blade.php b/resources/views/admin/invoice_edit.blade.php index 662bef7..dd203c4 100644 --- a/resources/views/admin/invoice_edit.blade.php +++ b/resources/views/admin/invoice_edit.blade.php @@ -33,6 +33,97 @@ body { 100% { opacity: 1; transform: translateY(0) scale(1); } } +/* -------------------------------------------------- + INVOICE PREVIEW RESPONSIVE FIXES +-------------------------------------------------- */ +.invoice-preview-wrapper { + width: 100%; + overflow: auto; + max-width: 100%; + box-sizing: border-box; +} + +.invoice-preview-wrapper * { + box-sizing: border-box; +} + +/* Override any fixed width styles that might be in popup_invoice */ +#invoicePreview, +.invoice-container, +.invoice-wrapper { + max-width: 100% !important; + width: 100% !important; +} + +/* Responsive table fixes for invoice */ +.invoice-preview-wrapper table { + width: 100% !important; + max-width: 100% !important; + table-layout: auto !important; +} + +.invoice-preview-wrapper .table-responsive { + overflow-x: auto !important; + -webkit-overflow-scrolling: touch; +} + +/* Ensure all elements scale properly */ +.invoice-preview-wrapper .row, +.invoice-preview-wrapper .col, +.invoice-preview-wrapper [class*="col-"] { + flex: 1 1 auto !important; + max-width: 100% !important; +} + +/* Force responsive behavior for print-style elements */ +@media (max-width: 1200px) { + .invoice-preview-wrapper { + font-size: 95%; + } +} + +@media (max-width: 992px) { + .invoice-preview-wrapper { + font-size: 90%; + } +} + +@media (max-width: 768px) { + .invoice-preview-wrapper { + font-size: 85%; + } + + .invoice-preview-wrapper table th, + .invoice-preview-wrapper table td { + padding: 0.5rem !important; + } +} + +@media (max-width: 576px) { + .invoice-preview-wrapper { + font-size: 80%; + } + + .invoice-preview-wrapper .d-flex { + flex-direction: column !important; + } + + .invoice-preview-wrapper .text-end, + .invoice-preview-wrapper .text-start { + text-align: center !important; + } +} + +/* Prevent any fixed pixel widths */ +.invoice-preview-wrapper [style*="width:"]:not([style*="width:100%"]):not([style*="width:auto"]) { + width: auto !important; + max-width: 100% !important; +} + +.invoice-preview-wrapper [style*="min-width"] { + min-width: 0 !important; +} + /* -------------------------------------------------- COMPACT CARD DESIGN -------------------------------------------------- */ @@ -332,6 +423,30 @@ body { font-size: 0.8rem; } } + +@media print { + .invoice-preview-wrapper { + max-width: 100% !important; + width: 100% !important; + overflow: visible !important; + } + + .invoice-preview-wrapper * { + visibility: visible !important; + } + + .glass-card { + box-shadow: none !important; + border: 1px solid #000 !important; + } + + .card-header-compact { + background: #000 !important; + color: #fff !important; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; + } +} @@ -344,7 +459,7 @@ body { Invoice Overview -
+
@include('admin.popup_invoice', [ 'invoice' => $invoice, 'shipment' => $shipment, diff --git a/resources/views/admin/popup_invoice.blade.php b/resources/views/admin/popup_invoice.blade.php index ce9392b..b02a7b6 100644 --- a/resources/views/admin/popup_invoice.blade.php +++ b/resources/views/admin/popup_invoice.blade.php @@ -56,7 +56,7 @@ } .id-container { - margin-bottom: 1rem; /* Reduced from 1.5rem */ + margin-bottom: 1rem; } .id-box { @@ -67,6 +67,9 @@ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); transition: all 0.3s ease; height: 100%; + display: flex; + align-items: center; + gap: 1rem; } .id-box:hover { @@ -82,34 +85,29 @@ border-left: 4px solid var(--success); } - .id-box-accent { - border-left: 4px solid var(--warning); - } - .id-icon { - width: 36px; - height: 36px; - border-radius: 50%; + width: 48px; + height: 48px; + border-radius: var(--border-radius); display: flex; align-items: center; justify-content: center; - margin-bottom: 0.5rem; /* Reduced from 0.75rem */ - font-size: 1rem; + font-size: 1.2rem; + flex-shrink: 0; } .id-icon-primary { - background: rgba(52, 152, 219, 0.1); - color: var(--secondary); + background: linear-gradient(135deg, #3498db 0%, #2980b9 100%); + color: white; } .id-icon-secondary { - background: rgba(39, 174, 96, 0.1); - color: var(--success); + background: linear-gradient(135deg, #27ae60 0%, #219653 100%); + color: white; } - .id-icon-accent { - background: rgba(243, 156, 18, 0.1); - color: var(--warning); + .id-content { + flex: 1; } .id-label { @@ -126,76 +124,87 @@ font-weight: 700; color: var(--primary); margin-bottom: 0; + word-break: break-word; + line-height: 1.3; } - .date-container { - background: white; - border-radius: var(--border-radius); - padding: 1rem; /* Reduced from 1.25rem */ - margin-bottom: 1rem; /* Reduced from 1.5rem */ - border: 1px solid #e9ecef; - box-shadow: var(--box-shadow); - } - - .date-card { - text-align: center; - padding: 0.75rem; - background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); - border-radius: var(--border-radius); - border: 1px solid rgba(0,0,0,0.05); - } - - .date-icon { - width: 40px; - height: 40px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - margin: 0 auto 0.5rem; /* Reduced from 0.75rem */ - background: var(--secondary); + /* Enhanced Date Section with Blue-Purple Gradient */ + .date-badge { + font-size: 0.85rem; + padding: 0.75rem 1rem; + border-radius: 8px; + font-weight: 500; + background: linear-gradient(135deg, #3498db 0%, #9b59b6 100%); color: white; - font-size: 1rem; + border: none; + min-width: 140px; + position: relative; + overflow: hidden; + box-shadow: 0 4px 15px rgba(52, 152, 219, 0.2); } - .date-label { - font-size: 0.8rem; - color: #6c757d; - font-weight: 600; - margin-bottom: 0.5rem; + .date-badge:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(52, 152, 219, 0.3); + } + + .date-badge .badge-label { + font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.5px; - } - - .date-value { - font-size: 1rem; - font-weight: 700; - color: var(--primary); - padding: 0.5rem; - background: white; - border-radius: 4px; - border: 1px solid #e9ecef; - } - - .date-connector { + color: rgba(255, 255, 255, 0.9); + margin-bottom: 0.25rem; display: flex; align-items: center; - justify-content: center; - height: 100%; + gap: 4px; } - .date-connector i { - background: var(--light); - padding: 10px; + .date-badge .badge-label i { + font-size: 0.6rem; + } + + .date-badge .badge-value { + font-weight: 700; + font-size: 0.95rem; + color: white; + } + + .date-badge.due-date { + background: linear-gradient(135deg, #3498db 0%, #9b59b6 100%); + } + + .date-badge.overdue { + background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%); + animation: pulse 2s infinite; + } + + @keyframes pulse { + 0% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0.4); } + 70% { box-shadow: 0 0 0 6px rgba(231, 76, 60, 0); } + 100% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0); } + } + + .date-separator { + color: #dee2e6; + font-weight: 300; + padding: 0 0.5rem; + display: flex; + align-items: center; + } + + .date-separator i { + background: white; + padding: 8px; border-radius: 50%; color: var(--secondary); border: 2px solid #e9ecef; + box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .card { border: 1px solid #e9ecef; border-radius: var(--border-radius); - margin-bottom: 1rem; /* Reduced from 1.5rem */ + margin-bottom: 1rem; box-shadow: var(--box-shadow); } @@ -228,27 +237,18 @@ background-color: rgba(52, 152, 219, 0.03); } - .summary-card { - background: var(--light); - border-left: 4px solid var(--secondary); - } - - .summary-header { - background: var(--primary); - color: white; + /* Simplified Summary Section */ + .summary-container { + margin: 2rem 0; } .amount-row { - border-bottom: 1px solid #e9ecef; + display: flex; + justify-content: space-between; + align-items: center; padding: 0.75rem 0; } - .total-row { - border-top: 2px solid #dee2e6; - font-size: 1.1rem; - font-weight: 700; - } - .text-primary { color: var(--primary) !important; } @@ -268,15 +268,20 @@ /* COMPACT HEADER STYLES */ .compact-header { - margin-bottom: 0.75rem; /* Reduced from default */ + margin-bottom: 0.75rem; } .compact-header .invoice-title { - margin-bottom: 0.25rem; /* Reduced gap */ + margin-bottom: 0.25rem; } - .compact-header .status-badge { - margin-top: 0.25rem; /* Reduced gap */ + /* Date and status row */ + .date-status-row { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 0.75rem; + flex-wrap: wrap; } @media (max-width: 768px) { @@ -284,10 +289,6 @@ margin: 1rem; } - .date-connector { - margin: 1rem 0; - } - .table-responsive { font-size: 0.8rem; } @@ -295,6 +296,55 @@ .id-box { margin-bottom: 1rem; } + + .date-status-row { + justify-content: flex-start; + margin-top: 0.5rem; + } + + .compact-header .col-md-6.text-end { + text-align: left !important; + } + + .date-badge { + min-width: 120px; + } + + .summary-container { + padding: 0 1rem; + } + } + + @media (max-width: 576px) { + .date-status-row { + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + } + + .date-separator { + display: none; + } + + .date-badge { + width: 100%; + } + + .id-box { + flex-direction: column; + text-align: center; + gap: 0.75rem; + } + + .id-icon { + width: 40px; + height: 40px; + font-size: 1rem; + } + + .table-responsive { + overflow-x: auto; + } } @@ -318,108 +368,89 @@
- - - {{ ucfirst($invoice->status) }} - -
-
- - - -
-
- -
-
-
- +
+ +
+
+ INVOICE DATE +
+
{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }}
-
Invoice ID
-
{{ $invoice->invoice_number }}
-
-
- - -
-
-
- -
-
Order ID
-
- @if($invoice->order && $invoice->order->order_id) - {{ $invoice->order->order_id }} - @elseif($invoice->order_id) - {{ $invoice->order_id }} - @else - N/A - @endif -
-
-
- - -
-
-
- -
-
Shipment ID
-
- @php - $shipmentId = 'N/A'; - // Try multiple ways to get shipment ID - if($invoice->shipment && $invoice->shipment->shipment_id) { - $shipmentId = $invoice->shipment->shipment_id; - } elseif($invoice->shipment_id) { - $shipmentId = $invoice->shipment_id; - } elseif(isset($shipment) && $shipment && $shipment->shipment_id) { - $shipmentId = $shipment->shipment_id; - } - @endphp - {{ $shipmentId }} + + +
+
+ DUE DATE +
+
{{ \Carbon\Carbon::parse($invoice->due_date)->format('M d, Y') }}
+ + + + + {{ ucfirst($invoice->status) }} +
-
-
-
-
-
- +
+
+ +
+
+
+ +
+
+
ORDER ID
+
+ @if($invoice->order && $invoice->order->order_id) + {{ $invoice->order->order_id }} + @elseif($invoice->order_id) + {{ $invoice->order_id }} + @else + N/A + @endif +
-
INVOICE DATE
-
{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }}
-
-
- -
-
-
-
-
- + + +
+
+
+
-
DUE DATE
-
- {{ \Carbon\Carbon::parse($invoice->due_date)->format('M d, Y') }} +
+
SHIPMENT ID
+
+ @php + $shipmentId = 'N/A'; + // Try multiple ways to get shipment ID + if($invoice->shipment && $invoice->shipment->shipment_id) { + $shipmentId = $invoice->shipment->shipment_id; + } elseif($invoice->shipment_id) { + $shipmentId = $invoice->shipment_id; + } elseif(isset($shipment) && $shipment && $shipment->shipment_id) { + $shipmentId = $shipment->shipment_id; + } + @endphp + {{ $shipmentId }} +
@@ -519,78 +550,71 @@
- -
-
-
-
-
- Final Summary -
-
-
-
- Amount: - ₹{{ number_format($invoice->final_amount,2) }} -
+ @php + $totalAmount = $invoice->final_amount; + $gstAmount = $invoice->gst_amount; + $totalPayable = $invoice->final_amount_with_gst; - @if($invoice->tax_type === 'gst') - {{-- CGST --}} -
- CGST ({{ $invoice->cgst_percent ?? ($invoice->gst_percent/2) }}%): - ₹{{ number_format($invoice->gst_amount/2, 2) }} -
+ $paidAmount = $invoice->totalPaid(); + $remaining = $invoice->remainingAmount(); + @endphp - {{-- SGST --}} -
- SGST ({{ $invoice->sgst_percent ?? ($invoice->gst_percent/2) }}%): - ₹{{ number_format($invoice->gst_amount/2, 2) }} -
+
+
+
- @elseif($invoice->tax_type === 'igst') - {{-- IGST --}} -
- IGST ({{ $invoice->igst_percent ?? $invoice->gst_percent }}%): - ₹{{ number_format($invoice->gst_amount, 2) }} -
- @else - {{-- Default GST --}} -
- GST ({{ $invoice->gst_percent }}%): - ₹{{ number_format($invoice->gst_amount, 2) }} -
- @endif - -
- Total Payable: - ₹{{ number_format($invoice->final_amount_with_gst,2) }} -
-
-
-
+
+ Total Amount + ₹{{ number_format($totalAmount,2) }}
+ +
+ GST Amount + + + ₹{{ number_format($gstAmount,2) }} + +
+ +
+ Total Payable + + ₹{{ number_format($totalPayable,2) }} + +
+ +
+ Paid Amount + + − ₹{{ number_format($paidAmount,2) }} + +
+ +
+ Remaining Amount + + ₹{{ number_format($remaining,2) }} + +
+ +
+
+
+
- @if($invoice->pdf_path) - + + Download PDF - @endif -
- - -
-

Thank you for your business!

-

For any inquiries, contact us at support@Kent Logistic

+
@@ -600,12 +624,12 @@ - + + \ No newline at end of file diff --git a/resources/views/admin/shipments.blade.php b/resources/views/admin/shipments.blade.php index 2d8be18..c0bb32d 100644 --- a/resources/views/admin/shipments.blade.php +++ b/resources/views/admin/shipments.blade.php @@ -734,17 +734,31 @@ text-decoration: underline; } - /* Shipment Details Modal */ + /* Shipment Details Modal - EDGE-TO-EDGE STYLING */ + .modal-xl.edge-to-edge { + max-width: 95vw !important; + width: 95vw !important; + margin: 1vh auto !important; + } + + /* UPDATED: Shipment Order Details Modal - ALSO EDGE-TO-EDGE */ + .modal-xl.edge-to-edge.order-details-modal { + max-width: 95vw !important; + width: 95vw !important; + margin: 1vh auto !important; + } + .shipment-details-header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; - padding: 25px 30px 15px; + padding: 25px 35px 15px; border-radius: 20px 20px 0 0; } .shipment-details-body { - padding: 40px 45px; + padding: 30px 35px; + width: 100%; } .shipment-info-row { @@ -824,47 +838,63 @@ border-bottom-right-radius: 10px; } - /* Shipment Totals Section */ + /* Shipment Totals Section - SINGLE ROW ON DESKTOP */ .shipment-totals { margin-top: 25px; - padding: 25px; + padding: 25px 20px; background: linear-gradient(135deg, #f8fafc, #e2e8f0); border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.05); border-left: 4px solid #4361ee; + width: 100%; } .shipment-totals-row { - display: flex; - flex-wrap: wrap; - gap: 20px; - justify-content: space-between; + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 12px; + justify-content: center; + align-items: stretch; + width: 100%; } .shipment-total-item { - flex: 1; - min-width: 150px; text-align: center; - padding: 15px; + padding: 15px 10px; background: white; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); + min-width: 0; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + flex-shrink: 1; } .shipment-total-label { font-weight: 600; color: #64748b; - font-size: 12px; + font-size: 11px; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.5px; + line-height: 1.2; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + width: 100%; } .shipment-total-value { font-weight: 800; - font-size: 20px; + font-size: 18px; color: #1e293b; line-height: 1.2; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + width: 100%; } .total-amount { @@ -873,6 +903,7 @@ padding: 10px; border-radius: 8px; border: 2px solid #10b981; + width: 100%; } .total-quantity { @@ -881,6 +912,7 @@ padding: 10px; border-radius: 8px; border: 2px solid #0ea5e9; + width: 100%; } .total-weight { @@ -889,6 +921,7 @@ padding: 10px; border-radius: 8px; border: 2px solid #8b5cf6; + width: 100%; } .total-cbm { @@ -897,6 +930,7 @@ padding: 10px; border-radius: 8px; border: 2px solid #ef4444; + width: 100%; } .total-ctn { @@ -905,6 +939,7 @@ padding: 10px; border-radius: 8px; border: 2px solid #f59e0b; + width: 100%; } .total-ttl-cbm { @@ -913,6 +948,7 @@ padding: 10px; border-radius: 8px; border: 2px solid #8b5cf6; + width: 100%; } .total-ttl-kg { @@ -921,6 +957,7 @@ padding: 10px; border-radius: 8px; border: 2px solid #14b8a6; + width: 100%; } /* Animation for loading */ @@ -964,8 +1001,8 @@ display: table-row; } - /* ---------- Pagination Styles ---------- */ - .pagination-container, .modal-pagination-container { + /* ---------- Pagination Styles (Same as Account Dashboard) ---------- */ + .pagination-container { display: flex; justify-content: space-between; align-items: center; @@ -974,19 +1011,19 @@ border-top: 1px solid #eef3fb; } - .pagination-info, .modal-pagination-info { + .pagination-info { font-size: 13px; color: #9ba5bb; font-weight: 600; } - .pagination-controls, .modal-pagination-controls { + .pagination-controls { display: flex; align-items: center; gap: 8px; } - .pagination-btn, .modal-pagination-btn { + .pagination-btn { background: #fff; border: 1px solid #e3eaf6; color: #1a2951; @@ -1003,13 +1040,13 @@ height: 32px; } - .pagination-btn:hover:not(:disabled), .modal-pagination-btn:hover:not(:disabled) { + .pagination-btn:hover:not(:disabled) { background: #1a2951; color: white; border-color: #1a2951; } - .pagination-btn:disabled, .modal-pagination-btn:disabled { + .pagination-btn:disabled { background: #f8fafc; color: #cbd5e0; border-color: #e2e8f0; @@ -1017,7 +1054,7 @@ opacity: 0.6; } - .pagination-page-btn, .modal-pagination-page-btn { + .pagination-page-btn { background: #fff; border: 1px solid #e3eaf6; color: #1a2951; @@ -1031,13 +1068,13 @@ text-align: center; } - .pagination-page-btn:hover, .modal-pagination-page-btn:hover { + .pagination-page-btn:hover { background: #1a2951; color: white; border-color: #1a2951; } - .pagination-page-btn.active, .modal-pagination-page-btn.active { + .pagination-page-btn.active { background: #1a2951; color: white; border-color: #1a2951; @@ -1055,16 +1092,210 @@ 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%); + } + + /* RESPONSIVE DESIGN FOR TABLET/MOBILE */ + @media (max-width: 1200px) { + .modal-xl.edge-to-edge { + max-width: 96vw !important; + width: 96vw !important; + margin: 2vh auto !important; + } + + .modal-xl.edge-to-edge.order-details-modal { + max-width: 96vw !important; + width: 96vw !important; + margin: 2vh auto !important; + } + + .shipment-totals-row { + grid-template-columns: repeat(4, 1fr); + gap: 15px; + } + } + + @media (max-width: 992px) { + .modal-xl.edge-to-edge { + max-width: 95vw !important; + width: 95vw !important; + margin: 2.5vh auto !important; + } + + .modal-xl.edge-to-edge.order-details-modal { + max-width: 95vw !important; + width: 95vw !important; + margin: 2.5vh auto !important; + } + + .shipment-details-body { + padding: 20px 25px; + } + + .shipment-totals-row { + grid-template-columns: repeat(3, 1fr); + } + } + @media (max-width: 768px) { - .pagination-container, .modal-pagination-container { + .pagination-container { flex-direction: column; gap: 10px; align-items: stretch; } - .pagination-controls, .modal-pagination-controls { + .pagination-controls { justify-content: center; } + + .modal-xl.edge-to-edge { + max-width: 100vw !important; + width: 100vw !important; + margin: 0 !important; + height: 100vh !important; + max-height: 100vh !important; + } + + .modal-xl.edge-to-edge.order-details-modal { + max-width: 100vw !important; + width: 100vw !important; + margin: 0 !important; + height: 100vh !important; + max-height: 100vh !important; + } + + .shipment-details-body { + padding: 15px 20px; + } + + .shipment-info-row { + flex-direction: column; + gap: 15px; + padding: 15px; + } + + .shipment-info-item { + padding: 10px 0; + } + + .shipment-totals { + padding: 20px 15px; + } + + .shipment-totals-row { + grid-template-columns: repeat(2, 1fr); + gap: 12px; + } + + .shipment-total-item { + padding: 12px 8px; + } + + .shipment-total-label { + font-size: 10px; + } + + .shipment-total-value { + font-size: 16px; + } + + /* Order details modal specific responsive styles */ + .order-details-content { + padding: 15px; + } + + .order-details-table { + min-width: 1000px; + } + } + + @media (max-width: 576px) { + .shipment-totals-row { + grid-template-columns: 1fr; + gap: 10px; + } + + .modal-xl.edge-to-edge .modal-content { + border-radius: 0; + height: 100vh; + overflow-y: auto; + } + + .modal-xl.edge-to-edge.order-details-modal .modal-content { + border-radius: 0; + height: 100vh; + overflow-y: auto; + } + + .shipment-details-header { + padding: 20px 25px 15px; + border-radius: 0; + } + + .order-details-header { + padding: 20px 15px 10px; + border-radius: 0; + } + + .order-details-body { + padding: 15px; + } + } + + @media (max-width: 480px) { + .modal-xl.edge-to-edge, + .modal-xl.edge-to-edge.order-details-modal { + margin: 0 !important; + padding: 0 !important; + } + + .modal-content { + border-radius: 0 !important; + } + + .shipment-details-body, + .order-details-body { + padding: 10px 15px; + } } @@ -1093,11 +1324,16 @@
- - - - + + + + + + + + + +
@@ -1333,14 +1562,14 @@
Showing 1 to {{ $shipments->count() }} of {{ $shipments->count() }} entries
-
- +
+ + +
+
+
+ @endsection \ No newline at end of file diff --git a/resources/views/admin/staff/create.blade.php b/resources/views/admin/staff/create.blade.php index a91e221..7fe1dfe 100644 --- a/resources/views/admin/staff/create.blade.php +++ b/resources/views/admin/staff/create.blade.php @@ -4,6 +4,7 @@ @section('content')