Fetch Data For Customer Details

This commit is contained in:
Utkarsh Khedkar
2026-03-12 12:34:27 +05:30
parent ff4c006ca4
commit 6b5876e08f
4 changed files with 253 additions and 212 deletions

View File

@@ -50,29 +50,22 @@ class AdminInvoiceController extends Controller
// POPUP VIEW // POPUP VIEW
// ------------------------------------------------------------- // -------------------------------------------------------------
public function popup($id) public function popup($id)
{ {
$invoice = Invoice::with([ $invoice = Invoice::with([
'items', 'items',
'chargeGroups.items', 'chargeGroups.items',
])->findOrFail($id); ])->findOrFail($id);
// demo update असेल तर $shipment = null;
$invoice->update([
'customer_email' => 'test@demo.com',
'customer_address' => 'TEST ADDRESS',
'pincode' => '999999',
]);
$shipment = null; $groupedItemIds = $invoice->chargeGroups
->flatMap(fn($group) => $group->items->pluck('invoice_item_id'))
->unique()
->values()
->toArray();
$groupedItemIds = $invoice->chargeGroups return view('admin.popup_invoice', compact('invoice', 'shipment', 'groupedItemIds'));
->flatMap(fn($group) => $group->items->pluck('invoice_item_id')) }
->unique()
->values()
->toArray();
return view('admin.popup_invoice', compact('invoice', 'shipment', 'groupedItemIds'));
}
// ------------------------------------------------------------- // -------------------------------------------------------------
// EDIT INVOICE PAGE // EDIT INVOICE PAGE
@@ -87,6 +80,28 @@ class AdminInvoiceController extends Controller
'installments', 'installments',
])->findOrFail($id); ])->findOrFail($id);
// ✅ Customer details sync — जर test data आला असेल तर fix होईल
if ($invoice->customer) {
$needsUpdate = [];
if (empty($invoice->customer_email) || $invoice->customer_email === 'test@demo.com') {
$needsUpdate['customer_email'] = $invoice->customer->email;
}
if (empty($invoice->customer_address) || $invoice->customer_address === 'TEST ADDRESS') {
$needsUpdate['customer_address'] = $invoice->customer->address;
}
if (empty($invoice->pincode) || $invoice->pincode === '999999') {
$needsUpdate['pincode'] = $invoice->customer->pincode;
}
if (!empty($needsUpdate)) {
$invoice->update($needsUpdate);
$invoice->refresh();
}
}
$shipment = null; $shipment = null;
$groupedItemIds = $invoice->chargeGroups $groupedItemIds = $invoice->chargeGroups

View File

@@ -520,7 +520,7 @@ class ContainerController extends Controller
$invoice = new Invoice(); $invoice = new Invoice();
$invoice->container_id = $container->id; $invoice->container_id = $container->id;
// $invoice->customer_id = $customerId; $invoice->customer_id = $customerId;
$invoice->mark_no = $firstMark; $invoice->mark_no = $firstMark;
$invoice->invoice_number = $this->generateInvoiceNumber(); $invoice->invoice_number = $this->generateInvoiceNumber();
@@ -533,20 +533,28 @@ class ContainerController extends Controller
->addDays(10) ->addDays(10)
->format('Y-m-d'); ->format('Y-m-d');
if ($snap) { // Customer User model वरून fetch करा (customer_id string आहे जसे CID-2025-000001)
$invoice->customer_name = $snap['customer_name'] ?? null; $customerUser = \App\Models\User::where('customer_id', $customerId)->first();
$invoice->company_name = $snap['company_name'] ?? null;
$invoice->customer_mobile = $snap['mobile_no'] ?? null;
}
$invoice->final_amount = 0; $invoice->container_id = $container->id;
$invoice->gst_percent = 0; $invoice->customer_id = $customerUser->id ?? null; // ✅ integer id
$invoice->gst_amount = 0; $invoice->mark_no = $firstMark;
$invoice->final_amount_with_gst = 0;
$invoice->customer_email = null; if ($snap) {
$invoice->customer_address = null; $invoice->customer_name = $snap['customer_name'] ?? null;
$invoice->pincode = 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 घ्या
$invoice->customer_email = $customerUser->email ?? null;
$invoice->customer_address = $customerUser->address ?? null;
$invoice->pincode = $customerUser->pincode ?? null;
$uniqueMarks = array_unique(array_column($rowsForCustomer, 'mark')); $uniqueMarks = array_unique(array_column($rowsForCustomer, 'mark'));
$invoice->notes = 'Auto-created from Container ' . $container->container_number $invoice->notes = 'Auto-created from Container ' . $container->container_number

View File

@@ -672,11 +672,14 @@
); );
$isTotalColumn = $isTotalQty || $isTotalCbm || $isTotalKg || $isAmount; $isTotalColumn = $isTotalQty || $isTotalCbm || $isTotalKg || $isAmount;
// जर container pending नसेल तर सर्व fields readonly
$isReadOnly = $isTotalColumn || $container->status !== 'pending';
@endphp @endphp
<td> <td>
<input <input
type="text" type="text"
class="cm-cell-input {{ $isTotalColumn ? 'cm-cell-readonly' : '' }}" class="cm-cell-input {{ $isReadOnly ? 'cm-cell-readonly' : '' }}"
name="rows[{{ $row->id }}][{{ $heading }}]" name="rows[{{ $row->id }}][{{ $heading }}]"
value="{{ $value }}" value="{{ $value }}"
data-row-id="{{ $row->id }}" data-row-id="{{ $row->id }}"
@@ -690,10 +693,11 @@
data-ttlkg="{{ $isTotalKg ? '1' : '0' }}" data-ttlkg="{{ $isTotalKg ? '1' : '0' }}"
data-price="{{ $isPrice ? '1' : '0' }}" data-price="{{ $isPrice ? '1' : '0' }}"
data-amount="{{ $isAmount ? '1' : '0' }}" data-amount="{{ $isAmount ? '1' : '0' }}"
@if($isTotalColumn) readonly @endif {{ $isReadOnly ? 'readonly' : '' }}
> >
</td> </td>
@endforeach @endforeach
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
@@ -706,186 +710,195 @@
</div> </div>
@if(!$container->rows->isEmpty()) @if(!$container->rows->isEmpty())
<button id="cmSaveBtnFloating" class="cm-save-btn-floating"> <button
Save Changes id="cmSaveBtnFloating"
</button> class="cm-save-btn-floating {{ $container->status !== 'pending' ? 'cm-disabled' : '' }}"
<div id="cmToast" class="cm-toast"> {{ $container->status !== 'pending' ? 'disabled' : '' }}
Changes saved successfully. >
</div> Save Changes
</button>
@endif @endif
<script> <script>
function cmFilterRows() { function cmFilterRows() {
const input = document.getElementById('cmRowSearch'); const input = document.getElementById('cmRowSearch');
if (!input) return; if (!input) return;
const filter = input.value.toLowerCase(); const filter = input.value.toLowerCase();
const table = document.getElementById('cmExcelTable'); const table = document.getElementById('cmExcelTable');
if (!table) return; if (!table) return;
const rows = table.getElementsByTagName('tr'); const rows = table.getElementsByTagName('tr');
for (let i = 1; i < rows.length; i++) { for (let i = 1; i < rows.length; i++) {
const cells = rows[i].getElementsByTagName('td'); const cells = rows[i].getElementsByTagName('td');
let match = false; let match = false;
for (let j = 0; j < cells.length; j++) { for (let j = 0; j < cells.length; j++) {
const txt = cells[j].textContent || cells[j].innerText; const txt = cells[j].textContent || cells[j].innerText;
if (txt.toLowerCase().indexOf(filter) > -1) { if (txt.toLowerCase().indexOf(filter) > -1) {
match = true; match = true;
break; break;
}
} }
rows[i].style.display = match ? '' : 'none'; }
rows[i].style.display = match ? '' : 'none';
}
}
document.addEventListener('DOMContentLoaded', function () {
const form = document.getElementById('cm-edit-rows-form');
const btn = document.getElementById('cmSaveBtnFloating');
const toast = document.getElementById('cmToast');
const table = document.getElementById('cmExcelTable');
function showToast(message, isError = false) {
if (!toast) return;
toast.textContent = message;
toast.style.background = isError ? '#b91c1c' : '#0f172a';
toast.classList.add('cm-show');
setTimeout(() => toast.classList.remove('cm-show'), 2500);
}
function parseNumber(str) {
if (!str) return 0;
const cleaned = String(str).replace(/,/g, '').trim();
const val = parseFloat(cleaned);
return isNaN(val) ? 0 : val;
}
function formatNumber(val, decimals) {
if (isNaN(val)) val = 0;
return val.toFixed(decimals);
}
function recalcRow(row) {
const inputs = row.querySelectorAll('.cm-cell-input');
let ctn = 0, qty = 0, ttlQty = 0;
let cbm = 0, ttlCbm = 0;
let kg = 0, ttlKg = 0;
let price = 0, amount = 0;
let ctnInput = null,
qtyInput = null,
ttlQtyInput = null,
cbmInput = null,
ttlCbmInput = null,
kgInput = null,
ttlKgInput = null,
priceInput = null,
amountInput = null;
inputs.forEach(inp => {
const val = parseNumber(inp.value);
if (inp.dataset.ctn === '1') {
ctn = val;
ctnInput = inp;
} else if (inp.dataset.qty === '1') {
qty = val;
qtyInput = inp;
} else if (inp.dataset.ttlqty === '1') {
ttlQty = val;
ttlQtyInput = inp;
} else if (inp.dataset.cbm === '1') {
cbm = val;
cbmInput = inp;
} else if (inp.dataset.ttlcbm === '1') {
ttlCbm = val;
ttlCbmInput = inp;
} else if (inp.dataset.kg === '1') {
kg = val;
kgInput = inp;
} else if (inp.dataset.ttlkg === '1') {
ttlKg = val;
ttlKgInput = inp;
} else if (inp.dataset.price === '1') {
price = val;
priceInput = inp;
} else if (inp.dataset.amount === '1') {
amount = val;
amountInput = inp;
}
});
if (ttlQtyInput && ctnInput && qtyInput) {
const newTtlQty = ctn * qty;
ttlQtyInput.value = formatNumber(newTtlQty, 0);
ttlQty = newTtlQty;
}
if (ttlCbmInput && cbmInput && ctnInput) {
const newTtlCbm = cbm * ctn;
ttlCbmInput.value = formatNumber(newTtlCbm, 3);
ttlCbm = newTtlCbm;
}
if (ttlKgInput && kgInput && ctnInput) {
const newTtlKg = kg * ctn;
ttlKgInput.value = formatNumber(newTtlKg, 2);
ttlKg = newTtlKg;
}
if (amountInput && priceInput && ttlQtyInput) {
const newAmount = price * ttlQty;
amountInput.value = formatNumber(newAmount, 2);
amount = newAmount;
} }
} }
document.addEventListener('DOMContentLoaded', function () { if (table) {
const form = document.getElementById('cm-edit-rows-form'); table.addEventListener('input', function (e) {
const btn = document.getElementById('cmSaveBtnFloating'); const target = e.target;
const toast = document.getElementById('cmToast'); if (!target.classList.contains('cm-cell-input')) return;
const table = document.getElementById('cmExcelTable');
function showToast(message, isError = false) { // readonly / non-pending cells साठी block
if (!toast) return; if (target.classList.contains('cm-cell-readonly') || target.hasAttribute('readonly')) {
toast.textContent = message; target.blur();
toast.style.background = isError ? '#b91c1c' : '#0f172a'; return;
toast.classList.add('cm-show');
setTimeout(() => toast.classList.remove('cm-show'), 2500);
}
function parseNumber(str) {
if (!str) return 0;
const cleaned = String(str).replace(/,/g, '').trim();
const val = parseFloat(cleaned);
return isNaN(val) ? 0 : val;
}
function formatNumber(val, decimals) {
if (isNaN(val)) val = 0;
return val.toFixed(decimals);
}
function recalcRow(row) {
const inputs = row.querySelectorAll('.cm-cell-input');
let ctn = 0, qty = 0, ttlQty = 0;
let cbm = 0, ttlCbm = 0;
let kg = 0, ttlKg = 0;
let price = 0, amount = 0;
let ctnInput = null,
qtyInput = null,
ttlQtyInput = null,
cbmInput = null,
ttlCbmInput = null,
kgInput = null,
ttlKgInput = null,
priceInput = null,
amountInput = null;
inputs.forEach(inp => {
const val = parseNumber(inp.value);
if (inp.dataset.ctn === '1') {
ctn = val;
ctnInput = inp;
} else if (inp.dataset.qty === '1') {
qty = val;
qtyInput = inp;
} else if (inp.dataset.ttlqty === '1') {
ttlQty = val;
ttlQtyInput = inp;
} else if (inp.dataset.cbm === '1') {
cbm = val;
cbmInput = inp;
} else if (inp.dataset.ttlcbm === '1') {
ttlCbm = val;
ttlCbmInput = inp;
} else if (inp.dataset.kg === '1') {
kg = val;
kgInput = inp;
} else if (inp.dataset.ttlkg === '1') {
ttlKg = val;
ttlKgInput = inp;
} else if (inp.dataset.price === '1') {
price = val;
priceInput = inp;
} else if (inp.dataset.amount === '1') {
amount = val;
amountInput = inp;
}
});
if (ttlQtyInput && ctnInput && qtyInput) {
const newTtlQty = ctn * qty;
ttlQtyInput.value = formatNumber(newTtlQty, 0);
ttlQty = newTtlQty;
} }
if (ttlCbmInput && cbmInput && ctnInput) { const row = target.closest('tr');
const newTtlCbm = cbm * ctn; if (row) {
ttlCbmInput.value = formatNumber(newTtlCbm, 3); recalcRow(row);
ttlCbm = newTtlCbm; }
});
}
if (form && btn) {
btn.addEventListener('click', function () {
// जर बटण आधीच disabled असेल (non-pending status किंवा processing)
if (btn.classList.contains('cm-disabled') || btn.hasAttribute('disabled')) {
return;
} }
if (ttlKgInput && kgInput && ctnInput) { btn.classList.add('cm-disabled');
const newTtlKg = kg * ctn; const formData = new FormData(form);
ttlKgInput.value = formatNumber(newTtlKg, 2);
ttlKg = newTtlKg;
}
if (amountInput && priceInput && ttlQtyInput) { fetch(form.action, {
const newAmount = price * ttlQty; method: 'POST',
amountInput.value = formatNumber(newAmount, 2); headers: {
amount = newAmount; 'X-Requested-With': 'XMLHttpRequest',
} 'X-CSRF-TOKEN': document.querySelector('input[name="_token"]').value
} },
body: formData
if (table) { })
table.addEventListener('input', function (e) { .then(async res => {
const target = e.target; if (!res.ok) {
if (!target.classList.contains('cm-cell-input')) return; const text = await res.text();
throw new Error(text || 'Failed to save');
if (target.classList.contains('cm-cell-readonly') || target.hasAttribute('readonly')) { }
target.blur(); return res.json().catch(() => ({}));
return;
}
const row = target.closest('tr');
if (row) {
recalcRow(row);
}
});
}
if (form && btn) {
btn.addEventListener('click', function () {
btn.classList.add('cm-disabled');
const formData = new FormData(form);
fetch(form.action, {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-TOKEN': document.querySelector('input[name="_token"]').value
},
body: formData
}) })
.then(async res => { .then(() => {
if (!res.ok) { showToast('Changes saved successfully.');
const text = await res.text(); })
throw new Error(text || 'Failed to save'); .catch(() => {
} showToast('Error while saving changes.', true);
return res.json().catch(() => ({})); })
}) .finally(() => {
.then(() => { btn.classList.remove('cm-disabled');
showToast('Changes saved successfully.'); });
}) });
.catch(() => { }
showToast('Error while saving changes.', true); });
})
.finally(() => {
btn.classList.remove('cm-disabled');
});
});
}
});
</script> </script>
@endsection @endsection

View File

@@ -893,20 +893,25 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="customer-name">{{ $invoice->customer_name }}</div> <div class="customer-name">{{ $invoice->customer_name }}</div>
@if($invoice->company_name) @if($invoice->company_name)
<div class="customer-detail"><strong>Company:</strong> {{ $invoice->company_name }}</div> <div class="customer-detail"><strong>Company:</strong> {{ $invoice->company_name }}</div>
@endif @endif
<div class="customer-detail"><strong>Mobile:</strong> {{ $invoice->customer_mobile }}</div> <div class="customer-detail"><strong>Mobile:</strong> {{ $invoice->customer_mobile }}</div>
<div class="customer-detail"><strong>Email:</strong> {{ $invoice->customer_email }}</div> <div class="customer-detail"><strong>Email:</strong>
{{ $invoice->customer_email ?: ($invoice->customer->email ?? '-') }}
</div>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="customer-detail"><strong>Address:</strong></div> <div class="customer-detail"><strong>Address:</strong></div>
<div class="customer-detail">{{ $invoice->customer_address }}</div> <div class="customer-detail">
<div class="customer-detail"><strong>Pincode:</strong> {{ $invoice->pincode }}</div> {{ $invoice->customer_address ?: ($invoice->customer->address ?? '-') }}
</div>
<div class="customer-detail"><strong>Pincode:</strong>
{{ $invoice->pincode ?: ($invoice->customer->pincode ?? '-') }}
</div>
</div> </div>
</div>
</div> </div>
</div> </div>