388 lines
17 KiB
PHP
388 lines
17 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../session.php';
|
|
require '../config.php';
|
|
require '../include_header.php';
|
|
?>
|
|
|
|
<body>
|
|
<?php require '../include_topbar.php'; ?>
|
|
<?php require '../include_setting_sidebar.php'; ?>
|
|
|
|
<main id="content" class="content py-15">
|
|
<div class="container-fluid">
|
|
|
|
<!-- Page header -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-6 gap-3">
|
|
<div>
|
|
<h1 class="fs-3 mb-1">System Configuration</h1>
|
|
<p class="mb-0">Per-company settings that control application behaviour</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Warehouse Location Settings -->
|
|
<div class="row">
|
|
<div class="col-12 col-lg-7">
|
|
<div class="card border-0 shadow-sm mb-5">
|
|
<div class="card-header bg-transparent border-bottom">
|
|
<h6 class="mb-0"><i class="ti ti-map-pin me-2"></i>Warehouse Location Settings</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
|
|
<div class="mb-4">
|
|
<label class="form-label fw-semibold">Advanced Location</label>
|
|
<p class="text-muted small mb-2">
|
|
By default, each storage location uses a single <strong>Location</strong> field —
|
|
ideal for small warehouses. Enable <strong>Advanced</strong> to use a three-level
|
|
hierarchy (e.g. Zone → Aisle → Bin) for larger operations.
|
|
You can customise the label for each level to match your team's terminology.
|
|
</p>
|
|
<div class="form-check form-switch mb-3">
|
|
<input class="form-check-input" type="checkbox" id="advanced_location_toggle" value="1">
|
|
<label class="form-check-label" for="advanced_location_toggle">
|
|
Enable Advanced Location
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Simple mode — single label -->
|
|
<div id="location_simple">
|
|
<div class="row g-3 align-items-center">
|
|
<div class="col-auto">
|
|
<label class="col-form-label text-muted small">Location Label</label>
|
|
</div>
|
|
<div class="col-lg-4">
|
|
<input type="text" id="location_label_bin_simple" class="form-control form-control-sm"
|
|
placeholder="Location" maxlength="30">
|
|
</div>
|
|
<div class="col-auto">
|
|
<span class="text-muted small">default: "Location"</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Advanced mode — three labels -->
|
|
<div id="location_advanced" class="d-none">
|
|
<div class="row g-3 align-items-center mb-2">
|
|
<div class="col-auto" style="width:100px">
|
|
<label class="col-form-label text-muted small">Level 1 Label</label>
|
|
</div>
|
|
<div class="col-lg-4">
|
|
<input type="text" id="location_label_zone" class="form-control form-control-sm"
|
|
placeholder="Zone" maxlength="30">
|
|
</div>
|
|
<div class="col-auto">
|
|
<span class="text-muted small">default: "Zone"</span>
|
|
</div>
|
|
</div>
|
|
<div class="row g-3 align-items-center mb-2">
|
|
<div class="col-auto" style="width:100px">
|
|
<label class="col-form-label text-muted small">Level 2 Label</label>
|
|
</div>
|
|
<div class="col-lg-4">
|
|
<input type="text" id="location_label_aisle" class="form-control form-control-sm"
|
|
placeholder="Aisle" maxlength="30">
|
|
</div>
|
|
<div class="col-auto">
|
|
<span class="text-muted small">default: "Aisle"</span>
|
|
</div>
|
|
</div>
|
|
<div class="row g-3 align-items-center">
|
|
<div class="col-auto" style="width:100px">
|
|
<label class="col-form-label text-muted small">Level 3 Label</label>
|
|
</div>
|
|
<div class="col-lg-4">
|
|
<input type="text" id="location_label_bin_advanced" class="form-control form-control-sm"
|
|
placeholder="Bin" maxlength="30">
|
|
</div>
|
|
<div class="col-auto">
|
|
<span class="text-muted small">default: "Bin"</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button class="btn btn-primary" onclick="save_config();">
|
|
<i class="ti ti-device-floppy me-1"></i>Save
|
|
</button>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stock Settings -->
|
|
<div class="row">
|
|
<div class="col-12 col-lg-7">
|
|
<div class="card border-0 shadow-sm mb-5">
|
|
<div class="card-header bg-transparent border-bottom">
|
|
<h6 class="mb-0"><i class="ti ti-package me-2"></i>Stock Settings</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
|
|
<div class="mb-4">
|
|
<label class="form-label fw-semibold">Default Stock Status</label>
|
|
<p class="text-muted small mb-2">
|
|
Controls whether new stock-in, stock-out, and transfer records are saved
|
|
as <strong>Draft</strong> (requires manual approval) or
|
|
<strong>Auto-approved</strong> (approved immediately on save).
|
|
Only approved records appear in reports and balance calculations.
|
|
</p>
|
|
<div class="d-flex flex-column gap-2" id="default_stock_status_group">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="default_stock_status"
|
|
id="status_auto" value="1">
|
|
<label class="form-check-label" for="status_auto">
|
|
<span class="fw-semibold">Auto-approve</span>
|
|
<span class="text-muted ms-1 small">— records are approved immediately on save</span>
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="default_stock_status"
|
|
id="status_draft" value="0">
|
|
<label class="form-check-label" for="status_draft">
|
|
<span class="fw-semibold">Draft</span>
|
|
<span class="text-muted ms-1 small">— records must be manually approved before affecting reports</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button class="btn btn-primary" onclick="save_config();">
|
|
<i class="ti ti-device-floppy me-1"></i>Save
|
|
</button>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Order Fulfillment Settings -->
|
|
<div class="card border-0 shadow-sm mb-5">
|
|
<div class="card-header bg-transparent border-bottom">
|
|
<h6 class="mb-0"><i class="ti ti-truck me-2"></i>Order Fulfillment Settings</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
|
|
<div class="mb-4">
|
|
<label class="form-label fw-semibold">Auto-Complete on Shipped</label>
|
|
<p class="text-muted small mb-2">
|
|
Controls whether an order is automatically marked as <strong>Completed</strong>
|
|
when its fulfillment status is set to <strong>Shipped</strong>.
|
|
When <strong>Manual</strong>, the order stays in Processing and staff
|
|
must mark it Completed themselves.
|
|
</p>
|
|
<div class="d-flex flex-column gap-2" id="auto_complete_on_ship_group">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="auto_complete_on_ship"
|
|
id="complete_auto" value="1">
|
|
<label class="form-check-label" for="complete_auto">
|
|
<span class="fw-semibold">Auto</span>
|
|
<span class="text-muted ms-1 small">— order is completed automatically when shipped</span>
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="auto_complete_on_ship"
|
|
id="complete_manual" value="0">
|
|
<label class="form-check-label" for="complete_manual">
|
|
<span class="fw-semibold">Manual</span>
|
|
<span class="text-muted ms-1 small">— staff mark the order as completed manually</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button class="btn btn-primary" onclick="save_config();">
|
|
<i class="ti ti-device-floppy me-1"></i>Save
|
|
</button>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Invoice & Credit Note Settings -->
|
|
<div class="card border-0 shadow-sm">
|
|
<div class="card-header bg-transparent border-bottom">
|
|
<h6 class="mb-0"><i class="ti ti-file-invoice me-2"></i>Invoice & Credit Note Settings</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
|
|
<div class="mb-4">
|
|
<label class="form-label fw-semibold">Invoice & Credit Note Generation</label>
|
|
<p class="text-muted small mb-2">
|
|
Controls automatic document generation.
|
|
When <strong>Auto</strong> is selected, a draft invoice is created when an order is confirmed,
|
|
and a credit note is created automatically when a return is confirmed.
|
|
When <strong>Manual</strong>, staff create these documents themselves from the order or return detail page.
|
|
</p>
|
|
<div class="d-flex flex-column gap-2" id="auto_invoice_and_credit_note_group">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="auto_invoice_and_credit_note"
|
|
id="invoice_auto" value="1">
|
|
<label class="form-check-label" for="invoice_auto">
|
|
<span class="fw-semibold">Auto</span>
|
|
<span class="text-muted ms-1 small">— invoice on order confirm, credit note on return confirm</span>
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="auto_invoice_and_credit_note"
|
|
id="invoice_manual" value="0">
|
|
<label class="form-check-label" for="invoice_manual">
|
|
<span class="fw-semibold">Manual</span>
|
|
<span class="text-muted ms-1 small">— staff create invoice and credit note manually</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button class="btn btn-primary" onclick="save_config();">
|
|
<i class="ti ti-device-floppy me-1"></i>Save
|
|
</button>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</main>
|
|
|
|
<?php require '../include_ending.php'; ?>
|
|
|
|
<script>
|
|
|
|
// ── Load ──────────────────────────────────────────────────────────────────
|
|
$(function() {
|
|
ajax_request({
|
|
url: server_url + 'setting/api/engine/company_setting.php',
|
|
autoPrepare: true,
|
|
checkRequired: 0,
|
|
action: 'read',
|
|
onSuccess: function(res) {
|
|
var s = res.output;
|
|
|
|
// Location settings
|
|
var advanced = (s.advanced_location ?? 0) == 1;
|
|
$('#advanced_location_toggle').prop('checked', advanced);
|
|
toggle_location_mode(advanced);
|
|
$('#location_label_bin_simple').val(s.location_label_bin || '');
|
|
$('#location_label_zone').val(s.location_label_zone || '');
|
|
$('#location_label_aisle').val(s.location_label_aisle || '');
|
|
$('#location_label_bin_advanced').val(s.location_label_bin || '');
|
|
|
|
// Other settings
|
|
$('input[name="default_stock_status"][value="' + (s.default_stock_status ?? 1) + '"]').prop('checked', true);
|
|
$('input[name="auto_complete_on_ship"][value="' + (s.auto_complete_on_ship ?? 1) + '"]').prop('checked', true);
|
|
$('input[name="auto_invoice_and_credit_note"][value="' + (s.auto_invoice_and_credit_note ?? 0) + '"]').prop('checked', true);
|
|
|
|
apply_setting_locks(res.locked || {});
|
|
}
|
|
});
|
|
|
|
// Toggle advanced/simple panels on switch change
|
|
$('#advanced_location_toggle').on('change', function() {
|
|
toggle_location_mode($(this).is(':checked'));
|
|
});
|
|
});
|
|
|
|
function toggle_location_mode(advanced) {
|
|
if (advanced) {
|
|
$('#location_simple').addClass('d-none');
|
|
$('#location_advanced').removeClass('d-none');
|
|
} else {
|
|
$('#location_simple').removeClass('d-none');
|
|
$('#location_advanced').addClass('d-none');
|
|
}
|
|
}
|
|
|
|
function apply_setting_locks(locked) {
|
|
set_setting_lock(
|
|
'advanced_location',
|
|
'#advanced_location_toggle',
|
|
locked.advanced_location,
|
|
'Advanced Location cannot be changed because stock transactions already exist. Location labels can still be renamed.'
|
|
);
|
|
set_setting_lock(
|
|
'default_stock_status',
|
|
'input[name="default_stock_status"]',
|
|
locked.default_stock_status,
|
|
'Default Stock Status cannot be changed because stock transactions already exist.'
|
|
);
|
|
set_setting_lock(
|
|
'auto_complete_on_ship',
|
|
'input[name="auto_complete_on_ship"]',
|
|
locked.auto_complete_on_ship,
|
|
'Auto-Complete on Shipped cannot be changed because order, invoice, or return transactions already exist.'
|
|
);
|
|
set_setting_lock(
|
|
'auto_invoice_and_credit_note',
|
|
'input[name="auto_invoice_and_credit_note"]',
|
|
locked.auto_invoice_and_credit_note,
|
|
'Invoice & Credit Note Generation cannot be changed because order, invoice, or return transactions already exist.'
|
|
);
|
|
}
|
|
|
|
function set_setting_lock(key, selector, is_locked, message) {
|
|
var $inputs = $(selector);
|
|
$inputs.prop('disabled', !!is_locked);
|
|
|
|
var $container = $inputs.first().closest('.mb-4');
|
|
$container.find('.setting-lock-note[data-lock-key="' + key + '"]').remove();
|
|
|
|
if (is_locked) {
|
|
$container.append(
|
|
'<div class="setting-lock-note text-warning small mt-2" data-lock-key="' + key + '">' +
|
|
'<i class="ti ti-lock me-1"></i>' + message +
|
|
'</div>'
|
|
);
|
|
}
|
|
}
|
|
|
|
// ── Save ──────────────────────────────────────────────────────────────────
|
|
function save_config() {
|
|
var advanced = $('#advanced_location_toggle').is(':checked') ? 1 : 0;
|
|
var stock_status = $('input[name="default_stock_status"]:checked').val();
|
|
var auto_invoice_and_cn = $('input[name="auto_invoice_and_credit_note"]:checked').val();
|
|
var auto_complete_on_ship = $('input[name="auto_complete_on_ship"]:checked').val();
|
|
|
|
if (stock_status === undefined || auto_invoice_and_cn === undefined || auto_complete_on_ship === undefined) {
|
|
bootbox.alert('Please select all settings before saving.');
|
|
return;
|
|
}
|
|
|
|
// Resolve label values — fall back to defaults if blank
|
|
var label_bin, label_zone, label_aisle;
|
|
if (advanced) {
|
|
label_zone = $('#location_label_zone').val().trim() || 'Zone';
|
|
label_aisle = $('#location_label_aisle').val().trim() || 'Aisle';
|
|
label_bin = $('#location_label_bin_advanced').val().trim() || 'Bin';
|
|
} else {
|
|
label_bin = $('#location_label_bin_simple').val().trim() || 'Location';
|
|
label_zone = label_bin;
|
|
label_aisle = label_bin;
|
|
}
|
|
|
|
ajax_request({
|
|
url: server_url + 'setting/api/engine/company_setting.php',
|
|
autoPrepare: true,
|
|
checkRequired: 0,
|
|
action: 'update',
|
|
data: {
|
|
advanced_location: advanced,
|
|
location_label_zone: label_zone,
|
|
location_label_aisle: label_aisle,
|
|
location_label_bin: label_bin,
|
|
default_stock_status: stock_status,
|
|
auto_invoice_and_credit_note: auto_invoice_and_cn,
|
|
auto_complete_on_ship: auto_complete_on_ship,
|
|
},
|
|
onSuccess: function() {
|
|
bootbox.alert('Settings saved.');
|
|
}
|
|
});
|
|
}
|
|
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|