diff --git a/app/Http/Controllers/Admin/AdminInvoiceController.php b/app/Http/Controllers/Admin/AdminInvoiceController.php index d2cc567..9a14f97 100644 --- a/app/Http/Controllers/Admin/AdminInvoiceController.php +++ b/app/Http/Controllers/Admin/AdminInvoiceController.php @@ -130,7 +130,7 @@ class AdminInvoiceController extends Controller $data = $request->validate([ 'invoice_date' => 'required|date', 'due_date' => 'required|date|after_or_equal:invoice_date', - 'status' => 'required|in:pending,paid,overdue', + 'status' => 'required|in:pending,paying,paid,overdue', 'notes' => 'nullable|string', ]); @@ -149,8 +149,8 @@ class AdminInvoiceController extends Controller $this->generateInvoicePDF($invoice); return redirect() - ->route('admin.invoices.index') - ->with('success', 'Invoice updated & PDF generated successfully.'); + ->route('admin.invoices.edit', $invoice->id) + ->with('success', 'Invoice updated & PDF generated successfully.'); } // ------------------------------------------------------------- diff --git a/app/Http/Controllers/ContainerController.php b/app/Http/Controllers/ContainerController.php index eb6d89a..b948702 100644 --- a/app/Http/Controllers/ContainerController.php +++ b/app/Http/Controllers/ContainerController.php @@ -11,7 +11,7 @@ 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 +use Illuminate\Support\Facades\Storage; class ContainerController extends Controller { @@ -518,9 +518,12 @@ 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 = $customerId; + $invoice->customer_id = $customerUser->id ?? null; // ✅ integer id store करतोय $invoice->mark_no = $firstMark; $invoice->invoice_number = $this->generateInvoiceNumber(); @@ -533,28 +536,24 @@ class ContainerController extends Controller ->addDays(10) ->format('Y-m-d'); - // Customer User model वरून fetch करा (customer_id string आहे जसे CID-2025-000001) - $customerUser = \App\Models\User::where('customer_id', $customerId)->first(); - - $invoice->container_id = $container->id; - $invoice->customer_id = $customerUser->id ?? null; // ✅ integer id - $invoice->mark_no = $firstMark; - - if ($snap) { - $invoice->customer_name = $snap['customer_name'] ?? null; - $invoice->company_name = $snap['company_name'] ?? null; - $invoice->customer_mobile = $snap['mobile_no'] ?? null; - } - - $invoice->final_amount = 0; - $invoice->gst_percent = 0; - $invoice->gst_amount = 0; - $invoice->final_amount_with_gst = 0; - - // ✅ User model वरून email, address, pincode घ्या + // ✅ 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; $invoice->pincode = $customerUser->pincode ?? null; + } + + $invoice->final_amount = 0; + $invoice->gst_percent = 0; + $invoice->gst_amount = 0; + $invoice->final_amount_with_gst = 0; $uniqueMarks = array_unique(array_column($rowsForCustomer, 'mark')); $invoice->notes = 'Auto-created from Container ' . $container->container_number @@ -621,7 +620,18 @@ class ContainerController extends Controller public function show(Container $container) { $container->load('rows'); - return view('admin.container_show', compact('container')); + + // paid invoices च्या row indexes collect करा + $lockedRowIndexes = \App\Models\Invoice::where('invoices.container_id', $container->id) + ->where('invoices.status', 'paid') + ->join('invoice_items', 'invoices.id', '=', 'invoice_items.invoice_id') + ->pluck('invoice_items.container_row_index') + ->filter() + ->unique() + ->values() + ->toArray(); + + return view('admin.container_show', compact('container', 'lockedRowIndexes')); } public function updateRows(Request $request, Container $container) @@ -879,73 +889,71 @@ class ContainerController extends Controller return Storage::download($path, $fileName); } - public function popupPopup(Container $container) -{ - // existing show सारखाच data वापरू - $container->load('rows'); + { + // existing show सारखाच data वापरू + $container->load('rows'); - // summary आधीपासून index() मध्ये जसा काढतोस तसाच logic reuse - $rows = $container->rows ?? collect(); + // summary आधीपासून index() मध्ये जसा काढतोस तसाच logic reuse + $rows = $container->rows ?? collect(); - $totalCtn = 0; - $totalQty = 0; - $totalCbm = 0; - $totalKg = 0; + $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']; + $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; - } + $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 ($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); + 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); } - return 0; - }; - foreach ($rows as $row) { - $data = $row->data ?? []; - if (!is_array($data)) continue; + $summary = [ + 'total_ctn' => round($totalCtn, 2), + 'total_qty' => round($totalQty, 2), + 'total_cbm' => round($totalCbm, 3), + 'total_kg' => round($totalKg, 2), + ]; - $totalCtn += $getFirstNumeric($data, $ctnKeys); - $totalQty += $getFirstNumeric($data, $qtyKeys); - $totalCbm += $getFirstNumeric($data, $cbmKeys); - $totalKg += $getFirstNumeric($data, $kgKeys); + return view('admin.partials.container_popup_readonly', [ + 'container' => $container, + 'summary' => $summary, + ]); } - - $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/Invoice.php b/app/Models/Invoice.php index eaba94c..bf2e258 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -119,4 +119,11 @@ class Invoice extends Model return max(0, $grand - $paid); } + + public function isLockedForEdit(): bool + { + return $this->status === 'paid'; + } + + } diff --git a/database/migrations/2026_03_12_053830_add_charge_columns_to_invoices_table.php b/database/migrations/2026_03_12_053830_add_charge_columns_to_invoices_table.php index 567740f..79adc4a 100644 --- a/database/migrations/2026_03_12_053830_add_charge_columns_to_invoices_table.php +++ b/database/migrations/2026_03_12_053830_add_charge_columns_to_invoices_table.php @@ -9,15 +9,29 @@ class AddChargeColumnsToInvoicesTable extends Migration public function up() { Schema::table('invoices', function (Blueprint $table) { - $table->decimal('charge_groups_total', 15, 2)->nullable()->after('final_amount_with_gst'); - $table->decimal('grand_total_with_charges', 15, 2)->nullable()->after('charge_groups_total'); + if (!Schema::hasColumn('invoices', 'charge_groups_total')) { + $table->decimal('charge_groups_total', 15, 2) + ->nullable() + ->after('final_amount_with_gst'); + } + + if (!Schema::hasColumn('invoices', 'grand_total_with_charges')) { + $table->decimal('grand_total_with_charges', 15, 2) + ->nullable() + ->after('charge_groups_total'); + } }); } public function down() { Schema::table('invoices', function (Blueprint $table) { - $table->dropColumn(['charge_groups_total', 'grand_total_with_charges']); + if (Schema::hasColumn('invoices', 'charge_groups_total')) { + $table->dropColumn('charge_groups_total'); + } + if (Schema::hasColumn('invoices', 'grand_total_with_charges')) { + $table->dropColumn('grand_total_with_charges'); + } }); } -} \ No newline at end of file +} diff --git a/database/migrations/2026_03_12_091307_alter_invoices_status_add_paying.php b/database/migrations/2026_03_12_091307_alter_invoices_status_add_paying.php new file mode 100644 index 0000000..ac5ceec --- /dev/null +++ b/database/migrations/2026_03_12_091307_alter_invoices_status_add_paying.php @@ -0,0 +1,23 @@ +row_index, $lockedRowIndexes ?? []); + $isReadOnly = $isTotalColumn || $container->status !== 'pending' || $isLockedByInvoice; + @endphp - // जर container pending नसेल तर सर्व fields readonly - $isReadOnly = $isTotalColumn || $container->status !== 'pending'; - @endphp + @if($loop->first && $isLockedByInvoice) + {{-- पहिल्या cell मध्ये lock icon --}} + @endif +
| + + | +# | +Description | +CTN | +QTY | +TTL/QTY | +Unit | +Price | +TTL Amount | +CBM | +TTL CBM | +KG | +TTL KG | +Shop No | +||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| + + | ++ {{ $i + 1 }} + | ++ {{ $item->description }} + | +{{ $item->ctn }} | +{{ $item->qty }} | +{{ $item->ttl_qty }} | +{{ $item->unit }} | + + @if($isEmbedded) ++ + | ++ + | + @else ++ ₹{{ number_format($item->price, 2) }} + | ++ ₹{{ number_format($item->ttl_amount, 2) }} + | + @endif + +{{ $item->cbm }} | +{{ $item->ttl_cbm }} | +{{ $item->kg }} | +{{ $item->ttl_kg }} | ++ {{ $item->shop_no }} + | +
|
+ + No invoice items found. + |
+ |||||||||||||||
| - - | -# | -Description | -CTN | -QTY | -TTL/QTY | -Unit | -Price | -TTL Amount | -CBM | -TTL CBM | -KG | -TTL KG | -Shop No | -||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| - - | -{{ $i + 1 }} | -{{ $item->description }} | -{{ $item->ctn }} | -{{ $item->qty }} | -{{ $item->ttl_qty }} | -{{ $item->unit }} | + {{-- Items pagination bar --}} +- - | -- - | - @else -₹{{ number_format($item->price, 2) }} | -₹{{ number_format($item->ttl_amount, 2) }} | - @endif + +{{ $item->cbm }} | -{{ $item->ttl_cbm }} | -{{ $item->kg }} | -{{ $item->ttl_kg }} | -{{ $item->shop_no }} | -
|
- No invoice items found. - |
- |||||||||||||||