Pdf Changes Done
This commit is contained in:
@@ -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,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user