warehouse layers [switchable]

This commit is contained in:
Thanakorn S
2026-05-04 13:43:32 +07:00
parent a90975d9f1
commit 414f1cd81d
26 changed files with 2022 additions and 584 deletions
+63 -18
View File
@@ -60,6 +60,12 @@
placeholder="DD/MM/YYYY" autocomplete="off">
</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">
</div>
<div class="mb-3 col-lg-12">
<label class="form-label">Notes</label>
<textarea id="notes" class="form-control" rows="2"
@@ -112,8 +118,10 @@
<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="tracking_number_display"></p>
</div>
</div>
@@ -172,7 +180,21 @@
<i class="ti ti-file-invoice me-1"></i>Proceed to Invoice
</button>
<!-- Update payment status (confirmed and above) -->
<!-- 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">
@@ -242,6 +264,15 @@
return map[String(status)] ?? '—';
}
function fulfillment_status_badge(status) {
const map = {
'1': '<span class="badge bg-warning text-dark"><i class="ti ti-list-check me-1"></i>Picking</span>',
'2': '<span class="badge bg-info text-white"><i class="ti ti-package me-1"></i>Packed</span>',
'3': '<span class="badge bg-success"><i class="ti ti-truck me-1"></i>Shipped</span>',
};
return map[String(status)] ?? '';
}
// ── Recalculate totals ────────────────────────────────────────────────────
function recalc_totals() {
@@ -346,37 +377,45 @@
// ── Set view/edit mode ────────────────────────────────────────────────────
function set_mode(status, has_active_invoice, returnable_count) {
function set_mode(status, has_active_invoice, returnable_count, fulfillment_status) {
status = parseInt(status);
has_active_invoice = has_active_invoice || false;
returnable_count = returnable_count ?? 1;
fulfillment_status = parseInt(fulfillment_status) || 0;
var is_draft = status === 0;
var can_confirm = status === 0;
var can_cancel = status === 0 || status === 1;
var is_cancelled = status === -1;
var is_completed = status === 3;
var can_fulfill = status >= 1 && !is_cancelled && !is_completed;
// Edit controls
$('#btn_add_item, #contact, #order_date, #notes, #discount, #tax, #shipping_fee')
.prop('disabled', !is_draft);
$('#shipping_tracking_number').prop('disabled', !(is_draft || can_fulfill));
$('.item_sku, .item_qty, .item_price, .item_warehouse').prop('disabled', !is_draft);
$('a[onclick^="remove_item"]').toggleClass('d-none', !is_draft);
// Action buttons — set_btn_state handles class swap + disabled + title
// 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_cancel', can_cancel && !is_cancelled,
is_cancelled ? 'Order is already cancelled' : 'Only draft or confirmed orders can be cancelled');
// Order status selector — confirmed and above, not cancelled
var can_change_status = status >= 1 && !is_cancelled;
$('#order_status_group').toggleClass('d-none', !can_change_status);
set_btn_state('#order_status_group button', can_change_status,
is_cancelled ? 'Order is cancelled' : 'Confirm the order first');
$('#order_status_select').prop('disabled', !can_change_status);
// 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
set_btn_state('#payment_status_group button', status >= 1 && !is_cancelled,
'Confirm the order before updating payment status');
$('#payment_status_select').prop('disabled', status < 1 || is_cancelled);
// Create Return
@@ -421,12 +460,17 @@
$('#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);
$('#tracking_number_display')
.toggleClass('d-none', !o.shipping_tracking_number)
.text(o.shipping_tracking_number ? 'Tracking: ' + o.shipping_tracking_number : '');
// 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 || '');
$('#notes').val(o.notes || '');
$('#discount').val(o.discount || 0);
$('#tax').val(o.tax || 0);
@@ -437,9 +481,8 @@
(o.items || []).forEach(function(item) { add_item_row(item); });
recalc_totals();
set_mode(o.status, res.has_active_invoice, (res.returnable_items || []).length);
set_mode(o.status, res.has_active_invoice, (res.returnable_items || []).length, o.fulfillment_status);
$('#payment_status_select').val(o.payment_status ?? 0);
$('#order_status_select').val(o.status);
}
});
}
@@ -470,6 +513,7 @@
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(),
},
onSuccess: function(res) {
@@ -508,16 +552,17 @@
}
// ── Update order status ───────────────────────────────────────────────────
function update_order_status() {
// ── 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,
status: $('#order_status_select').val(),
id: order_id,
fulfillment_status: $('#fulfillment_status_select').val(),
shipping_tracking_number: $('#shipping_tracking_number').val().trim(),
},
onSuccess: function() {
retrieve_order();
@@ -693,4 +738,4 @@
</script>
</body>
</html>
</html>