accounting workflows
This commit is contained in:
+173
-203
@@ -5,6 +5,8 @@
|
||||
|
||||
$order_id = (int)($_GET['id'] ?? 0);
|
||||
$is_edit = isset($_GET['edit']) || $order_id === 0;
|
||||
$source = $order_id ? '' : preg_replace('/[^a-z0-9_-]/i', '', $_GET['source'] ?? '');
|
||||
$source_id = $order_id ? 0 : (int)($_GET['source_id'] ?? 0);
|
||||
?>
|
||||
|
||||
<body>
|
||||
@@ -61,9 +63,10 @@
|
||||
</div>
|
||||
|
||||
<div class="mb-3 col-lg-6">
|
||||
<label class="form-label">Shipping Tracking Number</label>
|
||||
<input type="text" id="shipping_tracking_number" class="form-control"
|
||||
placeholder="Carrier tracking number..." maxlength="100" autocomplete="off">
|
||||
<label class="form-label">Department</label>
|
||||
<select id="department_id" class="form-select">
|
||||
<option value="0">— No Department —</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 col-lg-12">
|
||||
@@ -93,9 +96,10 @@
|
||||
<tr>
|
||||
<th>Product</th>
|
||||
<th>Warehouse</th>
|
||||
<th style="width:120px;">Qty</th>
|
||||
<th style="width:130px;">Unit Price</th>
|
||||
<th style="width:130px;">Total</th>
|
||||
<th style="width:90px;">Qty</th>
|
||||
<th style="width:120px;">Unit Price</th>
|
||||
<th style="width:80px;">Tax%</th>
|
||||
<th style="width:120px;">Total</th>
|
||||
<th style="width:40px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -117,14 +121,26 @@
|
||||
<h2 class="fs-5 mb-3">Status</h2>
|
||||
<div class="d-flex gap-2 mb-2">
|
||||
<span id="badge_status"></span>
|
||||
<span id="badge_payment"></span>
|
||||
<span id="badge_fulfillment"></span>
|
||||
</div>
|
||||
<p class="mb-0 small text-muted" id="order_number_display"></p>
|
||||
<p class="mb-0 small text-muted d-none" id="source_display"></p>
|
||||
<p class="mb-0 small text-muted d-none" id="tracking_number_display"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning d-none mb-5" id="pending_workflow_hint">
|
||||
<div class="d-flex gap-2">
|
||||
<i class="ti ti-building-warehouse mt-1"></i>
|
||||
<div>
|
||||
<div class="fw-semibold">Warehouse assignment required</div>
|
||||
<div class="small">
|
||||
Select a warehouse for every item, then save it. The order will move to Draft and can be confirmed.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Totals card -->
|
||||
<div class="card mb-5">
|
||||
<div class="card-body p-4">
|
||||
@@ -140,8 +156,12 @@
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Tax</span>
|
||||
<input type="number" id="tax" class="form-control form-control-sm text-end"
|
||||
style="width:110px;" value="0" min="0" oninput="recalc_totals()">
|
||||
<span id="summary_tax" class="fw-semibold">0.00</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<span class="text-muted small">Tax Adj.</span>
|
||||
<input type="number" id="tax_adjustment" class="form-control form-control-sm text-end"
|
||||
style="width:90px;" value="0" min="-0.3" max="0.3" step="0.01" oninput="recalc_totals()">
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<span class="text-muted">Shipping</span>
|
||||
@@ -180,36 +200,10 @@
|
||||
<i class="ti ti-file-invoice me-1"></i>Proceed to Invoice
|
||||
</button>
|
||||
|
||||
<!-- Update fulfillment status (confirmed and above) -->
|
||||
<div id="fulfillment_status_group">
|
||||
<label class="form-label small text-muted mb-1">Fulfillment Status</label>
|
||||
<div class="d-flex gap-2">
|
||||
<select id="fulfillment_status_select" class="form-select form-select-sm">
|
||||
<option value="1">Picking</option>
|
||||
<option value="2">Packed</option>
|
||||
<option value="3">Shipped</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-outline-primary text-nowrap"
|
||||
onclick="update_fulfillment_status()">
|
||||
<i class="ti ti-check"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="payment_status_group">
|
||||
<label class="form-label small text-muted mb-1">Payment Status</label>
|
||||
<div class="d-flex gap-2">
|
||||
<select id="payment_status_select" class="form-select form-select-sm">
|
||||
<option value="0">Unpaid</option>
|
||||
<option value="1">Paid</option>
|
||||
<option value="2">Partial</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-outline-primary text-nowrap"
|
||||
onclick="update_payment_status()">
|
||||
<i class="ti ti-check"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-outline-primary w-100" id="btn_tracking"
|
||||
onclick="update_tracking_number()">
|
||||
<i class="ti ti-truck-delivery me-1"></i>Save Tracking
|
||||
</button>
|
||||
<!-- Create Return (confirmed and above) -->
|
||||
<button class="btn btn-outline-warning w-100" id="btn_return"
|
||||
onclick="create_return()">
|
||||
@@ -234,8 +228,11 @@
|
||||
<?php require '../include_ending.php'; ?>
|
||||
|
||||
<script>
|
||||
// custom.js globals: remove_item(), init_product_search_inputs(), format_number()
|
||||
|
||||
var order_id = <?php echo $order_id; ?>;
|
||||
var order_source = <?php echo json_encode($source); ?>;
|
||||
var order_source_id = <?php echo (int)$source_id; ?>;
|
||||
var order_data = null;
|
||||
var warehouses = [];
|
||||
var item_index = 0;
|
||||
@@ -244,21 +241,10 @@
|
||||
// ── Status helpers ────────────────────────────────────────────────────────
|
||||
function order_status_badge(status) {
|
||||
const map = {
|
||||
'-2': '<span class="badge bg-danger">Pending — Awaiting Warehouse</span>',
|
||||
'-2': '<span class="badge bg-danger">Pending Warehouse</span>',
|
||||
'-1': '<span class="badge bg-secondary">Cancelled</span>',
|
||||
'0': '<span class="badge bg-warning text-dark">Draft</span>',
|
||||
'1': '<span class="badge bg-info text-white">Confirmed</span>',
|
||||
'2': '<span class="badge bg-primary">Processing</span>',
|
||||
'3': '<span class="badge bg-success">Completed</span>',
|
||||
};
|
||||
return map[String(status)] ?? '—';
|
||||
}
|
||||
|
||||
function payment_status_badge(status) {
|
||||
const map = {
|
||||
'0': '<span class="badge bg-warning text-dark">Unpaid</span>',
|
||||
'1': '<span class="badge bg-success">Paid</span>',
|
||||
'2': '<span class="badge bg-info text-white">Partial</span>',
|
||||
};
|
||||
return map[String(status)] ?? '—';
|
||||
}
|
||||
@@ -272,24 +258,45 @@
|
||||
return map[String(status)] ?? '';
|
||||
}
|
||||
|
||||
function source_display_label(source, source_id) {
|
||||
source = String(source || '').trim();
|
||||
source_id = parseInt(source_id) || 0;
|
||||
if (!source) return '';
|
||||
|
||||
const labels = {
|
||||
quotation: 'Quotation',
|
||||
api: 'API',
|
||||
marketplace: 'Marketplace',
|
||||
revenue: 'Revenue',
|
||||
};
|
||||
return (labels[source] || source) + (source_id > 0 ? ' #' + source_id : '');
|
||||
}
|
||||
|
||||
|
||||
// ── Recalculate totals ────────────────────────────────────────────────────
|
||||
function recalc_totals() {
|
||||
var subtotal = 0;
|
||||
var tax_sum = 0;
|
||||
$('#item_tbody tr').each(function() {
|
||||
var qty = parseFloat($(this).find('.item_qty').val()) || 0;
|
||||
var price = parseFloat($(this).find('.item_price').val()) || 0;
|
||||
var total = qty * price;
|
||||
var qty = parseFloat($(this).find('.item_qty').val()) || 0;
|
||||
var price = parseFloat($(this).find('.item_price').val()) || 0;
|
||||
var tax_rate = parseFloat($(this).find('.item_tax_rate').val()) || 0;
|
||||
var total = qty * price;
|
||||
var tax_amt = round_dp(total * tax_rate / 100, 4);
|
||||
$(this).find('.item_total').text(format_number(total, 2));
|
||||
$(this).find('.item_tax_amount').val(tax_amt);
|
||||
subtotal += total;
|
||||
tax_sum += tax_amt;
|
||||
});
|
||||
|
||||
var discount = parseFloat($('#discount').val()) || 0;
|
||||
var tax = parseFloat($('#tax').val()) || 0;
|
||||
var shipping_fee = parseFloat($('#shipping_fee').val()) || 0;
|
||||
var grand_total = subtotal - discount + tax + shipping_fee;
|
||||
var discount = parseFloat($('#discount').val()) || 0;
|
||||
var tax_adjustment = parseFloat($('#tax_adjustment').val()) || 0;
|
||||
var shipping_fee = parseFloat($('#shipping_fee').val()) || 0;
|
||||
var derived_tax = round_dp(tax_sum, 2);
|
||||
var grand_total = subtotal - discount + derived_tax + tax_adjustment + shipping_fee;
|
||||
|
||||
$('#summary_subtotal').text(format_number(subtotal, 2));
|
||||
$('#summary_tax').text(format_number(derived_tax, 2));
|
||||
$('#summary_grand_total').text(format_number(grand_total, 2));
|
||||
}
|
||||
|
||||
@@ -299,7 +306,7 @@
|
||||
item = item || {};
|
||||
var idx = item_index++;
|
||||
|
||||
var wh_options = warehouses.map(w =>
|
||||
var wh_options = '<option value="">Select warehouse</option>' + warehouses.map(w =>
|
||||
`<option value="${w.id}" ${item.warehouse_id == w.id ? 'selected' : ''}>${w.warehouse_name}</option>`
|
||||
).join('');
|
||||
|
||||
@@ -307,7 +314,7 @@
|
||||
<td>
|
||||
<input type="text" class="form-control form-control-sm item_sku product_search"
|
||||
placeholder="SKU..." value="${item.product_sku || ''}" autocomplete="off"
|
||||
data-idx="${idx}">
|
||||
data-idx="${idx}" data-product-name-target=".item_name">
|
||||
<input type="hidden" class="item_name" value="${item.product_name || ''}">
|
||||
<input type="hidden" class="item_id" value="${item.item_id ?? idx}">
|
||||
<small class="text-muted item_name_display">${item.product_name || ''}</small>
|
||||
@@ -323,9 +330,14 @@
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm item_price"
|
||||
value="${item.price || 0}" min="0" step="any" oninput="recalc_totals()">
|
||||
value="${item.unit_price || item.price || 0}" min="0" step="any" oninput="recalc_totals()">
|
||||
</td>
|
||||
<td class="item_total text-end">${format_number((item.quantity || 1) * (item.price || 0), 2)}</td>
|
||||
<td>
|
||||
<input type="number" class="form-control form-control-sm item_tax_rate"
|
||||
value="${parseFloat(item.tax_rate || 0).toFixed(2)}" min="0" max="100" step="0.01" oninput="recalc_totals()">
|
||||
<input type="hidden" class="item_tax_amount" value="${item.tax_amount || 0}">
|
||||
</td>
|
||||
<td class="item_total text-end">${format_number((item.quantity || 1) * (item.unit_price || item.price || 0), 2)}</td>
|
||||
<td>
|
||||
<a href="javascript:void(0);" class="link-danger" onclick="remove_item(${idx})">
|
||||
<i class="ti ti-trash fs-5"></i>
|
||||
@@ -334,13 +346,12 @@
|
||||
</tr>`;
|
||||
|
||||
$('#item_tbody').append(row);
|
||||
if (window.init_product_search_inputs) {
|
||||
window.init_product_search_inputs(`#item_row_${idx}`);
|
||||
}
|
||||
recalc_totals();
|
||||
}
|
||||
|
||||
function remove_item(idx) {
|
||||
$(`#item_row_${idx}`).remove();
|
||||
recalc_totals();
|
||||
}
|
||||
|
||||
|
||||
// ── Collect items from DOM ────────────────────────────────────────────────
|
||||
@@ -348,12 +359,15 @@
|
||||
var items = [];
|
||||
var idx = 0;
|
||||
$('#item_tbody tr').each(function() {
|
||||
var sku = $(this).find('.item_sku').val().trim();
|
||||
var name = $(this).find('.item_name').val().trim();
|
||||
var wh = parseInt($(this).find('.item_warehouse').val()) || 0;
|
||||
var qty = parseFloat($(this).find('.item_qty').val()) || 0;
|
||||
var price = parseFloat($(this).find('.item_price').val()) || 0;
|
||||
if (!sku || !wh || qty <= 0) { idx++; return; }
|
||||
var sku = $(this).find('.item_sku').val().trim();
|
||||
var name = $(this).find('.item_name').val().trim();
|
||||
var wh = parseInt($(this).find('.item_warehouse').val()) || 0;
|
||||
var qty = parseFloat($(this).find('.item_qty').val()) || 0;
|
||||
var price = parseFloat($(this).find('.item_price').val()) || 0;
|
||||
var tax_rate = parseFloat($(this).find('.item_tax_rate').val()) || 0;
|
||||
var tax_amt = parseFloat($(this).find('.item_tax_amount').val()) || 0;
|
||||
if (!sku || qty <= 0) { idx++; return; }
|
||||
if (!wh && !(!order_id && order_source)) { idx++; return; }
|
||||
items.push({
|
||||
item_id: idx,
|
||||
product_sku: sku,
|
||||
@@ -365,8 +379,10 @@
|
||||
lot_number: '',
|
||||
serial_number: '',
|
||||
quantity: qty,
|
||||
price: price,
|
||||
total_price: qty * price,
|
||||
unit_price: price,
|
||||
total_price: round_dp(qty * price, 4),
|
||||
tax_rate: tax_rate,
|
||||
tax_amount: tax_amt,
|
||||
stock_out_id: 0,
|
||||
});
|
||||
idx++;
|
||||
@@ -387,42 +403,33 @@
|
||||
var can_confirm = status === 0; // only Draft can be confirmed (not Pending)
|
||||
var can_cancel = status === -2 || status === 0 || status === 1;
|
||||
var is_cancelled = status === -1;
|
||||
var is_completed = status === 3;
|
||||
var can_fulfill = status >= 1 && !is_cancelled && !is_completed;
|
||||
var can_update_tracking = status === 1 && !is_cancelled;
|
||||
|
||||
// Edit controls
|
||||
$('#btn_add_item, #contact, #order_date, #notes, #discount, #tax, #shipping_fee')
|
||||
$('#btn_add_item, #contact, #order_date, #department_id, #notes, #discount, #tax_adjustment, #shipping_fee')
|
||||
.prop('disabled', !is_editable);
|
||||
$('#shipping_tracking_number').prop('disabled', !(is_editable || can_fulfill));
|
||||
$('.item_sku, .item_qty, .item_price, .item_warehouse').prop('disabled', !is_editable);
|
||||
$('.item_sku, .item_qty, .item_price, .item_tax_rate, .item_warehouse').prop('disabled', !is_editable);
|
||||
$('a[onclick^="remove_item"]').toggleClass('d-none', !is_editable);
|
||||
|
||||
// Pending hint
|
||||
if (is_pending) {
|
||||
$('#page_subtitle').text('Assign a warehouse for each item, then save to move this order to Draft.');
|
||||
$('#page_subtitle').text('Pending warehouse assignment');
|
||||
}
|
||||
$('#pending_workflow_hint').toggleClass('d-none', !is_pending);
|
||||
|
||||
// Action buttons
|
||||
set_btn_state('#btn_save', is_draft, 'Only draft orders can be edited');
|
||||
set_btn_state('#btn_confirm', can_confirm, 'Order must be in draft to confirm');
|
||||
set_btn_state('#btn_save', is_editable, 'Only pending or draft orders can be edited');
|
||||
$('#btn_save').html(is_pending
|
||||
? '<i class="ti ti-device-floppy me-1"></i>Save Warehouse'
|
||||
: '<i class="ti ti-device-floppy me-1"></i>Save Draft');
|
||||
set_btn_state('#btn_confirm', can_confirm,
|
||||
is_pending ? 'Assign warehouses and save first. The order will move to Draft.' : 'Order must be in draft to confirm');
|
||||
set_btn_state('#btn_cancel', can_cancel && !is_cancelled,
|
||||
is_cancelled ? 'Order is already cancelled' : 'Only draft or confirmed orders can be cancelled');
|
||||
|
||||
// Fulfillment status — confirmed and above, not cancelled, not completed
|
||||
$('#fulfillment_status_group').toggleClass('d-none', !can_fulfill);
|
||||
if (can_fulfill) {
|
||||
// Only show options ahead of current fulfillment
|
||||
$('#fulfillment_status_select option').each(function() {
|
||||
$(this).prop('disabled', parseInt($(this).val()) <= fulfillment_status);
|
||||
});
|
||||
// Default to next step
|
||||
var next = fulfillment_status + 1;
|
||||
if (next <= 3) $('#fulfillment_status_select').val(next);
|
||||
else $('#fulfillment_status_select').val(fulfillment_status);
|
||||
}
|
||||
|
||||
// Payment status selector
|
||||
$('#payment_status_select').prop('disabled', status < 1 || is_cancelled);
|
||||
set_btn_state('#btn_tracking', can_update_tracking,
|
||||
is_cancelled ? 'Order is cancelled'
|
||||
: status < 1 ? 'Confirm the order before adding a tracking number' : '');
|
||||
|
||||
// Create Return
|
||||
var can_return = status >= 1 && !is_cancelled && returnable_count > 0;
|
||||
@@ -464,21 +471,25 @@
|
||||
$('#page_subtitle').text('');
|
||||
$('#status_card').removeClass('d-none');
|
||||
$('#badge_status').html(order_status_badge(o.status));
|
||||
$('#badge_payment').html(payment_status_badge(o.payment_status));
|
||||
$('#badge_fulfillment').html(fulfillment_status_badge(o.fulfillment_status));
|
||||
$('#order_number_display').text(o.order_number);
|
||||
var source_label = source_display_label(o.source || '', o.source_id || 0);
|
||||
$('#source_display')
|
||||
.toggleClass('d-none', !source_label)
|
||||
.text(source_label ? 'Source: ' + source_label : '');
|
||||
var tracking = o.shipping_tracking_number || '';
|
||||
$('#tracking_number_display')
|
||||
.toggleClass('d-none', !o.shipping_tracking_number)
|
||||
.text(o.shipping_tracking_number ? 'Tracking: ' + o.shipping_tracking_number : '');
|
||||
.toggleClass('d-none', !tracking)
|
||||
.html(tracking ? '<i class="ti ti-truck-delivery me-1"></i>' + escape_html(tracking) : '');
|
||||
|
||||
// Fields
|
||||
$('#contact').val(o.contact_name || '');
|
||||
$('#contact_id').val(o.contact_id);
|
||||
$('#order_date').val(o.order_date ? format_date(o.order_date) : '');
|
||||
$('#shipping_tracking_number').val(o.shipping_tracking_number || '');
|
||||
$('#department_id').val(o.department_id || 0);
|
||||
$('#notes').val(o.notes || '');
|
||||
$('#discount').val(o.discount || 0);
|
||||
$('#tax').val(o.tax || 0);
|
||||
$('#tax_adjustment').val(o.tax_adjustment || 0);
|
||||
$('#shipping_fee').val(o.shipping_fee || 0);
|
||||
|
||||
// Items
|
||||
@@ -487,7 +498,6 @@
|
||||
|
||||
recalc_totals();
|
||||
set_mode(o.status, res.has_active_invoice, (res.returnable_items || []).length, o.fulfillment_status);
|
||||
$('#payment_status_select').val(o.payment_status ?? 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -495,6 +505,17 @@
|
||||
|
||||
// ── Save draft ────────────────────────────────────────────────────────────
|
||||
function save_order() {
|
||||
var missing_warehouse = false;
|
||||
$('#item_tbody tr').each(function() {
|
||||
var sku = $(this).find('.item_sku').val().trim();
|
||||
var wh = parseInt($(this).find('.item_warehouse').val()) || 0;
|
||||
if (sku && !wh) missing_warehouse = true;
|
||||
});
|
||||
if (missing_warehouse && !(!order_id && order_source)) {
|
||||
bootbox.alert('Select a warehouse for every item before saving.');
|
||||
return;
|
||||
}
|
||||
|
||||
var items = collect_items();
|
||||
if (!items.length) {
|
||||
bootbox.alert('Please add at least one item.');
|
||||
@@ -511,15 +532,17 @@
|
||||
checkRequired: 0,
|
||||
action: order_id ? 'update' : 'create',
|
||||
data: {
|
||||
id: order_id,
|
||||
contact_id: $('#contact_id').val() || 0,
|
||||
order_date: to_iso_date($('#order_date').val()),
|
||||
items: JSON.stringify(items),
|
||||
discount: $('#discount').val() || 0,
|
||||
tax: $('#tax').val() || 0,
|
||||
shipping_fee: $('#shipping_fee').val() || 0,
|
||||
shipping_tracking_number: $('#shipping_tracking_number').val().trim(),
|
||||
notes: $('#notes').val(),
|
||||
id: order_id,
|
||||
contact_id: $('#contact_id').val() || 0,
|
||||
department_id: $('#department_id').val() || 0,
|
||||
order_date: to_iso_date($('#order_date').val()),
|
||||
items: JSON.stringify(items),
|
||||
discount: $('#discount').val() || 0,
|
||||
tax_adjustment: $('#tax_adjustment').val() || 0,
|
||||
shipping_fee: $('#shipping_fee').val() || 0,
|
||||
source: order_id ? '' : order_source,
|
||||
source_id: order_id ? 0 : order_source_id,
|
||||
notes: $('#notes').val(),
|
||||
},
|
||||
onSuccess: function(res) {
|
||||
if (!order_id && res.new_id) {
|
||||
@@ -557,43 +580,33 @@
|
||||
}
|
||||
|
||||
|
||||
// ── Update fulfillment status ─────────────────────────────────────────────
|
||||
function update_fulfillment_status() {
|
||||
ajax_request({
|
||||
url: '<?php echo $server_url?>order/api/engine/update_order_status.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'update',
|
||||
data: {
|
||||
id: order_id,
|
||||
fulfillment_status: $('#fulfillment_status_select').val(),
|
||||
shipping_tracking_number: $('#shipping_tracking_number').val().trim(),
|
||||
},
|
||||
onSuccess: function() {
|
||||
retrieve_order();
|
||||
// ── Update tracking number ────────────────────────────────────────────────
|
||||
function update_tracking_number() {
|
||||
var current = (order_data && order_data.shipping_tracking_number) ? order_data.shipping_tracking_number : '';
|
||||
bootbox.prompt({
|
||||
title: '<i class="ti ti-truck-delivery me-2"></i>Shipping Tracking Number',
|
||||
value: current,
|
||||
inputType: 'text',
|
||||
placeholder: 'Enter carrier tracking number...',
|
||||
callback: function(result) {
|
||||
if (result === null) return;
|
||||
ajax_request({
|
||||
url: '<?php echo $server_url?>order/api/engine/update_order_status.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'update',
|
||||
data: {
|
||||
id: order_id,
|
||||
shipping_tracking_number: result.trim(),
|
||||
},
|
||||
onSuccess: function() {
|
||||
retrieve_order();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ── Update payment status ─────────────────────────────────────────────────
|
||||
function update_payment_status() {
|
||||
ajax_request({
|
||||
url: '<?php echo $server_url?>order/api/engine/update_payment_status.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'update',
|
||||
data: {
|
||||
id: order_id,
|
||||
payment_status: $('#payment_status_select').val(),
|
||||
},
|
||||
onSuccess: function() {
|
||||
retrieve_order();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ── Create return ─────────────────────────────────────────────────────────
|
||||
function create_return() {
|
||||
window.location.href = '<?php echo $server_url?>order/manage_return.php?order_id=' + order_id;
|
||||
@@ -656,67 +669,23 @@
|
||||
}
|
||||
|
||||
|
||||
// ── Contact autocomplete ──────────────────────────────────────────────────
|
||||
function init_contact_search() {
|
||||
$('#contact').autocomplete({
|
||||
source: function(req, res) {
|
||||
ajax_request({
|
||||
url: '<?php echo $server_url?>contact/api/engine/contact.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'read',
|
||||
data: { keyword: req.term },
|
||||
onSuccess: function(data) {
|
||||
res(data.output.map(c => ({
|
||||
label: c.contact_name,
|
||||
value: c.contact_name,
|
||||
id: c.id,
|
||||
})));
|
||||
}
|
||||
});
|
||||
},
|
||||
select: function(e, ui) {
|
||||
$('#contact_id').val(ui.item.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
$(document).on('contact:selected', '#contact', function(e, contact) {
|
||||
$('#contact_id').val(contact.id);
|
||||
});
|
||||
|
||||
|
||||
// ── Product autocomplete (per row) ────────────────────────────────────────
|
||||
function init_product_search() {
|
||||
$(document).on('input', '.item_sku', function() {
|
||||
var $input = $(this);
|
||||
var $row = $input.closest('tr');
|
||||
$input.autocomplete({
|
||||
source: function(req, res) {
|
||||
ajax_request({
|
||||
url: '<?php echo $server_url?>inventory/api/engine/product.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'read',
|
||||
data: { keyword: req.term },
|
||||
onSuccess: function(data) {
|
||||
res((data.output || []).map(p => ({
|
||||
label: p.sku + ' — ' + p.product_name,
|
||||
value: p.sku,
|
||||
name: p.product_name,
|
||||
})));
|
||||
}
|
||||
});
|
||||
},
|
||||
select: function(e, ui) {
|
||||
$row.find('.item_name').val(ui.item.name);
|
||||
$row.find('.item_name_display').text(ui.item.name);
|
||||
recalc_totals();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
$(document).on('product:selected', '.item_sku', function(e, product) {
|
||||
var $row = $(this).closest('tr');
|
||||
$row.find('.item_name').val(product.product_name || '');
|
||||
$row.find('.item_name_display').text(product.product_name || '');
|
||||
$row.find('.item_tax_rate').val(parseFloat(product.tax_rate || 0).toFixed(2));
|
||||
recalc_totals();
|
||||
});
|
||||
|
||||
|
||||
// ── Boot ─────────────────────────────────────────────────────────────────
|
||||
$(async function() {
|
||||
try {
|
||||
load_departments('department_id');
|
||||
await retrieve_warehouses();
|
||||
|
||||
if (order_id) {
|
||||
@@ -727,14 +696,15 @@
|
||||
$('#order_date').val(today);
|
||||
add_item_row();
|
||||
set_mode(0);
|
||||
if (order_source) {
|
||||
$('#page_title').text('New Revenue Sales Order');
|
||||
$('#page_subtitle').text('Create a pending sales order for WMS warehouse assignment');
|
||||
}
|
||||
}
|
||||
|
||||
// Init flatpickr on order date
|
||||
flatpickr('#order_date', { dateFormat: 'd/m/Y', allowInput: true });
|
||||
|
||||
init_contact_search();
|
||||
init_product_search();
|
||||
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user