my chnages in customer and staff
This commit is contained in:
@@ -68,24 +68,32 @@ class AdminOrderController extends Controller
|
|||||||
* ORDER ITEM MANAGEMENT (existing orders)
|
* ORDER ITEM MANAGEMENT (existing orders)
|
||||||
* ---------------------------*/
|
* ---------------------------*/
|
||||||
public function addItem(Request $request, $orderId)
|
public function addItem(Request $request, $orderId)
|
||||||
{
|
{
|
||||||
$order = Order::findOrFail($orderId);
|
$order = Order::findOrFail($orderId);
|
||||||
|
|
||||||
$data = $request->validate([
|
$data = $request->validate([
|
||||||
'description' => 'required|string',
|
'description' => 'required|string',
|
||||||
'ctn' => 'nullable|numeric',
|
'ctn' => 'nullable|numeric',
|
||||||
'qty' => 'nullable|numeric',
|
'qty' => 'nullable|numeric',
|
||||||
'ttl_qty' => 'nullable|numeric',
|
|
||||||
'unit' => 'nullable|string',
|
'unit' => 'nullable|string',
|
||||||
'price' => 'nullable|numeric',
|
'price' => 'nullable|numeric',
|
||||||
'ttl_amount' => 'nullable|numeric',
|
|
||||||
'cbm' => 'nullable|numeric',
|
'cbm' => 'nullable|numeric',
|
||||||
'ttl_cbm' => 'nullable|numeric',
|
|
||||||
'kg' => 'nullable|numeric',
|
'kg' => 'nullable|numeric',
|
||||||
'ttl_kg' => 'nullable|numeric',
|
|
||||||
'shop_no' => 'nullable|string',
|
'shop_no' => 'nullable|string',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// ✅ BACKEND CALCULATION
|
||||||
|
$ctn = (float) ($data['ctn'] ?? 0);
|
||||||
|
$qty = (float) ($data['qty'] ?? 0);
|
||||||
|
$price = (float) ($data['price'] ?? 0);
|
||||||
|
$cbm = (float) ($data['cbm'] ?? 0);
|
||||||
|
$kg = (float) ($data['kg'] ?? 0);
|
||||||
|
|
||||||
|
$data['ttl_qty'] = $ctn * $qty;
|
||||||
|
$data['ttl_amount'] = $data['ttl_qty'] * $price;
|
||||||
|
$data['ttl_cbm'] = $cbm * $ctn;
|
||||||
|
$data['ttl_kg'] = $ctn * $kg;
|
||||||
|
|
||||||
$data['order_id'] = $order->id;
|
$data['order_id'] = $order->id;
|
||||||
|
|
||||||
OrderItem::create($data);
|
OrderItem::create($data);
|
||||||
@@ -94,7 +102,8 @@ class AdminOrderController extends Controller
|
|||||||
$this->updateInvoiceFromOrder($order);
|
$this->updateInvoiceFromOrder($order);
|
||||||
|
|
||||||
return redirect()->back()->with('success', 'Item added and totals updated.');
|
return redirect()->back()->with('success', 'Item added and totals updated.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function deleteItem($id)
|
public function deleteItem($id)
|
||||||
{
|
{
|
||||||
@@ -500,14 +509,14 @@ class AdminOrderController extends Controller
|
|||||||
'items.*.description' => 'required|string',
|
'items.*.description' => 'required|string',
|
||||||
'items.*.ctn' => 'nullable|numeric',
|
'items.*.ctn' => 'nullable|numeric',
|
||||||
'items.*.qty' => 'nullable|numeric',
|
'items.*.qty' => 'nullable|numeric',
|
||||||
'items.*.ttl_qty' => 'nullable|numeric',
|
|
||||||
'items.*.unit' => 'nullable|string',
|
'items.*.unit' => 'nullable|string',
|
||||||
'items.*.price' => 'nullable|numeric',
|
'items.*.price' => 'nullable|numeric',
|
||||||
'items.*.ttl_amount' => 'nullable|numeric',
|
|
||||||
'items.*.cbm' => 'nullable|numeric',
|
'items.*.cbm' => 'nullable|numeric',
|
||||||
'items.*.ttl_cbm' => 'nullable|numeric',
|
|
||||||
'items.*.kg' => 'nullable|numeric',
|
'items.*.kg' => 'nullable|numeric',
|
||||||
'items.*.ttl_kg' => 'nullable|numeric',
|
|
||||||
'items.*.shop_no' => 'nullable|string',
|
'items.*.shop_no' => 'nullable|string',
|
||||||
])['items'];
|
])['items'];
|
||||||
|
|
||||||
@@ -520,6 +529,24 @@ class AdminOrderController extends Controller
|
|||||||
return back()->with('error', 'Add at least one item.');
|
return back()->with('error', 'Add at least one item.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ BACKEND CALCULATION (DO NOT TRUST FRONTEND)
|
||||||
|
foreach ($items as &$item) {
|
||||||
|
|
||||||
|
$ctn = (float) ($item['ctn'] ?? 0);
|
||||||
|
$qty = (float) ($item['qty'] ?? 0);
|
||||||
|
$price = (float) ($item['price'] ?? 0);
|
||||||
|
$cbm = (float) ($item['cbm'] ?? 0);
|
||||||
|
$kg = (float) ($item['kg'] ?? 0);
|
||||||
|
|
||||||
|
// Calculated fields
|
||||||
|
$item['ttl_qty'] = $ctn * $qty;
|
||||||
|
$item['ttl_amount'] = $item['ttl_qty'] * $price;
|
||||||
|
$item['ttl_cbm'] = $cbm * $ctn;
|
||||||
|
$item['ttl_kg'] = $ctn * $kg;
|
||||||
|
}
|
||||||
|
unset($item); // VERY IMPORTANT
|
||||||
|
|
||||||
|
|
||||||
// 3) totals
|
// 3) totals
|
||||||
$total_ctn = array_sum(array_column($items, 'ctn'));
|
$total_ctn = array_sum(array_column($items, 'ctn'));
|
||||||
$total_qty = array_sum(array_column($items, 'qty'));
|
$total_qty = array_sum(array_column($items, 'qty'));
|
||||||
@@ -631,22 +658,40 @@ class AdminOrderController extends Controller
|
|||||||
* UPDATE ORDER ITEM (existing orders)
|
* UPDATE ORDER ITEM (existing orders)
|
||||||
* ---------------------------*/
|
* ---------------------------*/
|
||||||
public function updateItem(Request $request, $id)
|
public function updateItem(Request $request, $id)
|
||||||
{
|
{
|
||||||
$item = OrderItem::findOrFail($id);
|
$item = OrderItem::findOrFail($id);
|
||||||
$order = $item->order;
|
$order = $item->order;
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'description' => 'required|string',
|
||||||
|
'ctn' => 'nullable|numeric',
|
||||||
|
'qty' => 'nullable|numeric',
|
||||||
|
'unit' => 'nullable|string',
|
||||||
|
'price' => 'nullable|numeric',
|
||||||
|
'cbm' => 'nullable|numeric',
|
||||||
|
'kg' => 'nullable|numeric',
|
||||||
|
'shop_no' => 'nullable|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ✅ BACKEND CALCULATION
|
||||||
|
$ctn = (float) ($request->ctn ?? 0);
|
||||||
|
$qty = (float) ($request->qty ?? 0);
|
||||||
|
$price = (float) ($request->price ?? 0);
|
||||||
|
$cbm = (float) ($request->cbm ?? 0);
|
||||||
|
$kg = (float) ($request->kg ?? 0);
|
||||||
|
|
||||||
$item->update([
|
$item->update([
|
||||||
'description' => $request->description,
|
'description' => $request->description,
|
||||||
'ctn' => $request->ctn,
|
'ctn' => $ctn,
|
||||||
'qty' => $request->qty,
|
'qty' => $qty,
|
||||||
'ttl_qty' => $request->ttl_qty,
|
'ttl_qty' => $ctn * $qty,
|
||||||
'unit' => $request->unit,
|
'unit' => $request->unit,
|
||||||
'price' => $request->price,
|
'price' => $price,
|
||||||
'ttl_amount' => $request->ttl_amount,
|
'ttl_amount' => ($ctn * $qty) * $price,
|
||||||
'cbm' => $request->cbm,
|
'cbm' => $cbm,
|
||||||
'ttl_cbm' => $request->ttl_cbm,
|
'ttl_cbm' => $cbm * $ctn,
|
||||||
'kg' => $request->kg,
|
'kg' => $kg,
|
||||||
'ttl_kg' => $request->ttl_kg,
|
'ttl_kg' => $ctn * $kg,
|
||||||
'shop_no' => $request->shop_no,
|
'shop_no' => $request->shop_no,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -654,7 +699,8 @@ class AdminOrderController extends Controller
|
|||||||
$this->updateInvoiceFromOrder($order);
|
$this->updateInvoiceFromOrder($order);
|
||||||
|
|
||||||
return back()->with('success', 'Item updated successfully');
|
return back()->with('success', 'Item updated successfully');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private function updateInvoiceFromOrder(Order $order)
|
private function updateInvoiceFromOrder(Order $order)
|
||||||
{
|
{
|
||||||
|
|||||||
BIN
public/invoices/invoice-INV-2025-000048.pdf
Normal file
BIN
public/invoices/invoice-INV-2025-000048.pdf
Normal file
Binary file not shown.
@@ -1570,23 +1570,97 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
const tr = document.createElement('tr');
|
const tr = document.createElement('tr');
|
||||||
tr.innerHTML = `
|
tr.innerHTML = `
|
||||||
<td class="align-middle fw-bold">${index + 1}</td>
|
<td class="align-middle fw-bold">${index + 1}</td>
|
||||||
<td><input type="text" class="form-control form-control-sm items-input" name="items[${index}][description]" data-field="description"></td>
|
|
||||||
<td><input type="number" class="form-control form-control-sm items-input" name="items[${index}][ctn]" data-field="ctn"></td>
|
<td>
|
||||||
<td><input type="number" class="form-control form-control-sm items-input" name="items[${index}][qty]" data-field="qty"></td>
|
<input type="text" class="form-control form-control-sm items-input"name="items[${index}][description]"data-field="description">
|
||||||
<td><input type="number" class="form-control form-control-sm items-input" name="items[${index}][ttl_qty]" data-field="ttl_qty"></td>
|
</td>
|
||||||
<td><input type="text" class="form-control form-control-sm items-input" name="items[${index}][unit]" data-field="unit"></td>
|
|
||||||
<td><input type="number" class="form-control form-control-sm items-input" name="items[${index}][price]" data-field="price" step="0.01"></td>
|
<td>
|
||||||
<td><input type="number" class="form-control form-control-sm items-input" name="items[${index}][ttl_amount]" data-field="ttl_amount" step="0.01"></td>
|
<input type="number" class="form-control form-control-sm items-input"name="items[${index}][ctn]"data-field="ctn">
|
||||||
<td><input type="number" class="form-control form-control-sm items-input" name="items[${index}][cbm]" data-field="cbm" step="0.001"></td>
|
</td>
|
||||||
<td><input type="number" class="form-control form-control-sm items-input" name="items[${index}][ttl_cbm]" data-field="ttl_cbm" step="0.001"></td>
|
|
||||||
<td><input type="number" class="form-control form-control-sm items-input" name="items[${index}][kg]" data-field="kg" step="0.001"></td>
|
<td>
|
||||||
<td><input type="number" class="form-control form-control-sm items-input" name="items[${index}][ttl_kg]" data-field="ttl_kg" step="0.001"></td>
|
<input type="number" class="form-control form-control-sm items-input"name="items[${index}][qty]"data-field="qty">
|
||||||
<td><input type="text" class="form-control form-control-sm items-input" name="items[${index}][shop_no]" data-field="shop_no"></td>
|
</td>
|
||||||
<td><button type="button" class="btn btn-sm btn-danger remove-row-btn">×</button></td>
|
|
||||||
|
<!-- 🔒 AUTO: TTL/QTY = CTN * QTY -->
|
||||||
|
<td>
|
||||||
|
<input type="number" class="form-control form-control-sm bg-light"name="items[${index}][ttl_qty]"data-field="ttl_qty"readonly>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<input type="text" class="form-control form-control-sm items-input"name="items[${index}][unit]"data-field="unit">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<input type="number" class="form-control form-control-sm items-input"name="items[${index}][price]"data-field="price"step="0.01">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<!-- 🔒 AUTO: TTL AMOUNT = TTL/QTY * PRICE -->
|
||||||
|
<td>
|
||||||
|
<input type="number" class="form-control form-control-sm bg-light"name="items[${index}][ttl_amount]"data-field="ttl_amount"step="0.001"readonly>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<input type="number" class="form-control form-control-sm items-input"name="items[${index}][cbm]"data-field="cbm"step="0.0001">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<!-- 🔒 AUTO: TTL CBM = CBM * QTY -->
|
||||||
|
<td>
|
||||||
|
<input type="number" class="form-control form-control-sm bg-light"name="items[${index}][ttl_cbm]"data-field="ttl_cbm"step="0.0001"readonly>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<input type="number" class="form-control form-control-sm items-input"name="items[${index}][kg]"data-field="kg"step="0.0001">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<!-- 🔒 AUTO: TTL KG = CTN * KG -->
|
||||||
|
<td>
|
||||||
|
<input type="number" class="form-control form-control-sm bg-light"name="items[${index}][ttl_kg]"data-field="ttl_kg"step="0.0001"readonly>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<input type="text" class="form-control form-control-sm items-input"name="items[${index}][shop_no]"data-field="shop_no">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-sm btn-danger remove-row-btn">×</button>
|
||||||
|
</td>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
itemsTableBody.appendChild(tr);
|
itemsTableBody.appendChild(tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function calculateRow(row) {
|
||||||
|
const ctn = parseFloat(row.querySelector('[data-field="ctn"]')?.value) || 0;
|
||||||
|
const qty = parseFloat(row.querySelector('[data-field="qty"]')?.value) || 0;
|
||||||
|
const price = parseFloat(row.querySelector('[data-field="price"]')?.value) || 0;
|
||||||
|
const cbm = parseFloat(row.querySelector('[data-field="cbm"]')?.value) || 0;
|
||||||
|
const kg = parseFloat(row.querySelector('[data-field="kg"]')?.value) || 0;
|
||||||
|
|
||||||
|
const ttlQty = ctn * qty;
|
||||||
|
const ttlAmount = ttlQty * price;
|
||||||
|
const ttlCbm = cbm * ctn;
|
||||||
|
const ttlKg = ctn * kg;
|
||||||
|
|
||||||
|
row.querySelector('[data-field="ttl_qty"]').value = ttlQty.toFixed(2);
|
||||||
|
row.querySelector('[data-field="ttl_amount"]').value = ttlAmount.toFixed(2);
|
||||||
|
row.querySelector('[data-field="ttl_cbm"]').value = ttlCbm.toFixed(3);
|
||||||
|
row.querySelector('[data-field="ttl_kg"]').value = ttlKg.toFixed(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
itemsTableBody.addEventListener('input', function (e) {
|
||||||
|
const row = e.target.closest('tr');
|
||||||
|
if (!row) return;
|
||||||
|
|
||||||
|
const calcFields = ['ctn', 'qty', 'price', 'cbm', 'kg'];
|
||||||
|
if (calcFields.includes(e.target.dataset.field)) {
|
||||||
|
calculateRow(row);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function generateDefaultRows() {
|
function generateDefaultRows() {
|
||||||
itemsTableBody.innerHTML = '';
|
itemsTableBody.innerHTML = '';
|
||||||
addRow(0);
|
addRow(0);
|
||||||
@@ -1971,7 +2045,7 @@ if (uploadExcelBtn && excelInput) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateItemsTable(items) {
|
function populateItemsTable(items) {
|
||||||
itemsTableBody.innerHTML = '';
|
itemsTableBody.innerHTML = '';
|
||||||
|
|
||||||
items.forEach((item, index) => {
|
items.forEach((item, index) => {
|
||||||
@@ -1979,21 +2053,21 @@ function populateItemsTable(items) {
|
|||||||
const row = itemsTableBody.children[index];
|
const row = itemsTableBody.children[index];
|
||||||
|
|
||||||
row.querySelector('[data-field="description"]').value = item.description ?? '';
|
row.querySelector('[data-field="description"]').value = item.description ?? '';
|
||||||
row.querySelector('[data-field="ctn"]').value = item.ctn ?? '';
|
row.querySelector('[data-field="ctn"]').value = item.ctn ?? 0;
|
||||||
row.querySelector('[data-field="qty"]').value = item.qty ?? '';
|
row.querySelector('[data-field="qty"]').value = item.qty ?? 0;
|
||||||
row.querySelector('[data-field="ttl_qty"]').value = item.ttl_qty ?? '';
|
|
||||||
row.querySelector('[data-field="unit"]').value = item.unit ?? '';
|
row.querySelector('[data-field="unit"]').value = item.unit ?? '';
|
||||||
row.querySelector('[data-field="price"]').value = item.price ?? '';
|
row.querySelector('[data-field="price"]').value= item.price ?? 0;
|
||||||
row.querySelector('[data-field="ttl_amount"]').value = item.ttl_amount ?? '';
|
row.querySelector('[data-field="cbm"]').value = item.cbm ?? 0;
|
||||||
row.querySelector('[data-field="cbm"]').value = item.cbm ?? '';
|
row.querySelector('[data-field="kg"]').value = item.kg ?? 0;
|
||||||
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 ?? '';
|
row.querySelector('[data-field="shop_no"]').value = item.shop_no ?? '';
|
||||||
|
|
||||||
|
// 🔥 ALWAYS RECALCULATE
|
||||||
|
calculateRow(row);
|
||||||
});
|
});
|
||||||
|
|
||||||
reindexRows();
|
reindexRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user