[test] contact to setting modules
This commit is contained in:
@@ -5,15 +5,19 @@
|
||||
require '../../../assets/utils/classes/WarehouseManager.php';
|
||||
require '../../../assets/utils/classes/CompanySettingManager.php';
|
||||
|
||||
$csm = new CompanySettingManager($pdo1, $company_id);
|
||||
$auto_approve = (int)$csm->get('default_stock_status') === 1;
|
||||
$csm = new CompanySettingManager($pdo1, $company_id);
|
||||
$auto_approve = (int)$csm->get('default_stock_status') === 1;
|
||||
|
||||
try {
|
||||
$new_id = null;
|
||||
try {
|
||||
// Ensure the per-warehouse stock table exists (older warehouses may not have it yet)
|
||||
$whBoot = new WarehouseManager($pdo2, $company_id);
|
||||
$whBoot->createStockTableForWarehouse((int)$data['warehouse']);
|
||||
|
||||
dbTransaction($pdo2, function($pdo) use ($data, $company_id, $logging, $uuid, $auto_approve, &$new_id) {
|
||||
$stock = new StockManager($pdo, $company_id);
|
||||
$whMgmt = new WarehouseManager($pdo, $company_id);
|
||||
$new_id = null;
|
||||
|
||||
dbTransaction($pdo2, function($pdo) use ($data, $company_id, $logging, $uuid, $auto_approve, &$new_id) {
|
||||
$stock = new StockManager($pdo, $company_id);
|
||||
$whMgmt = new WarehouseManager($pdo, $company_id);
|
||||
$new_id = $stock->saveStockIn($data, $logging, $uuid);
|
||||
|
||||
if ($auto_approve && $new_id > 0) {
|
||||
@@ -35,5 +39,5 @@
|
||||
http_response_code(400);
|
||||
}
|
||||
|
||||
exit(json_encode($answer));
|
||||
?>
|
||||
exit(json_encode($answer));
|
||||
?>
|
||||
|
||||
@@ -5,15 +5,19 @@
|
||||
require '../../../assets/utils/classes/WarehouseManager.php';
|
||||
require '../../../assets/utils/classes/CompanySettingManager.php';
|
||||
|
||||
$csm = new CompanySettingManager($pdo1, $company_id);
|
||||
$auto_approve = (int)$csm->get('default_stock_status') === 1;
|
||||
$csm = new CompanySettingManager($pdo1, $company_id);
|
||||
$auto_approve = (int)$csm->get('default_stock_status') === 1;
|
||||
|
||||
try {
|
||||
$new_id = null;
|
||||
try {
|
||||
// Ensure the per-warehouse stock table exists (older warehouses may not have it yet)
|
||||
$whBoot = new WarehouseManager($pdo2, $company_id);
|
||||
$whBoot->createStockTableForWarehouse((int)$data['warehouse']);
|
||||
|
||||
dbTransaction($pdo2, function($pdo) use ($data, $company_id, $logging, $uuid, $auto_approve, &$new_id) {
|
||||
$stock = new StockManager($pdo, $company_id);
|
||||
$whMgmt = new WarehouseManager($pdo, $company_id);
|
||||
$new_id = null;
|
||||
|
||||
dbTransaction($pdo2, function($pdo) use ($data, $company_id, $logging, $uuid, $auto_approve, &$new_id) {
|
||||
$stock = new StockManager($pdo, $company_id);
|
||||
$whMgmt = new WarehouseManager($pdo, $company_id);
|
||||
$new_id = $stock->saveStockOut($data, $logging, $uuid);
|
||||
|
||||
if ($auto_approve && $new_id > 0) {
|
||||
@@ -35,5 +39,5 @@
|
||||
http_response_code(400);
|
||||
}
|
||||
|
||||
exit(json_encode($answer));
|
||||
?>
|
||||
exit(json_encode($answer));
|
||||
?>
|
||||
|
||||
@@ -5,15 +5,20 @@
|
||||
require '../../../assets/utils/classes/WarehouseManager.php';
|
||||
require '../../../assets/utils/classes/CompanySettingManager.php';
|
||||
|
||||
$csm = new CompanySettingManager($pdo1, $company_id);
|
||||
$auto_approve = (int)$csm->get('default_stock_status') === 1;
|
||||
$csm = new CompanySettingManager($pdo1, $company_id);
|
||||
$auto_approve = (int)$csm->get('default_stock_status') === 1;
|
||||
|
||||
try {
|
||||
$new_id = null;
|
||||
try {
|
||||
// Ensure the per-warehouse stock tables exist (older warehouses may not have them yet)
|
||||
$whBoot = new WarehouseManager($pdo2, $company_id);
|
||||
$whBoot->createStockTableForWarehouse((int)$data['warehouse_from']);
|
||||
$whBoot->createStockTableForWarehouse((int)$data['warehouse_to']);
|
||||
|
||||
dbTransaction($pdo2, function($pdo) use ($data, $company_id, $logging, $uuid, $auto_approve, &$new_id) {
|
||||
$stock = new StockManager($pdo, $company_id);
|
||||
$whMgmt = new WarehouseManager($pdo, $company_id);
|
||||
$new_id = null;
|
||||
|
||||
dbTransaction($pdo2, function($pdo) use ($data, $company_id, $logging, $uuid, $auto_approve, &$new_id) {
|
||||
$stock = new StockManager($pdo, $company_id);
|
||||
$whMgmt = new WarehouseManager($pdo, $company_id);
|
||||
$new_id = $stock->saveStockTransfer($data, $logging, $uuid);
|
||||
|
||||
if ($auto_approve && $new_id > 0) {
|
||||
@@ -36,4 +41,4 @@
|
||||
}
|
||||
|
||||
exit(json_encode($answer));
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -104,6 +104,7 @@
|
||||
<!-- Submit Button -->
|
||||
<div class="mb-3 col-lg-12">
|
||||
<button type="submit" class="btn btn-primary" onclick="manage_stock_in();">Add Stock</button>
|
||||
<button type="button" class="btn btn-success ms-2 d-none" id="approve_stock_btn" onclick="approve_current_stock();">Approve</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -161,9 +162,15 @@
|
||||
|
||||
function manage_stock_in() {
|
||||
|
||||
// In simple mode, mirror rack value to zone and aisle
|
||||
var rack_val = $('#rack').val();
|
||||
var zone_val = advanced ? $('#zone').val() : rack_val;
|
||||
var aisle_val = advanced ? $('#aisle').val() : rack_val;
|
||||
var warehouse_val = $('#warehouse').val();
|
||||
var sku_val = $('#product_sku').attr('secondary') || $('#product_sku').val();
|
||||
var quantity_val = $('#quantity').val();
|
||||
|
||||
// Mirror to hidden inputs for autoPrepare consistency (simple mode)
|
||||
if (!advanced) {
|
||||
var rack_val = $('#rack').val();
|
||||
$('#zone').val(rack_val);
|
||||
$('#aisle').val(rack_val);
|
||||
}
|
||||
@@ -178,8 +185,12 @@
|
||||
'lot_number': $('#lot_number').val(),
|
||||
'expiry_date': $('#expiry_date').val(),
|
||||
'serial_number': $('#serial_number').val(),
|
||||
'zone': $('#zone').val(),
|
||||
'aisle': $('#aisle').val(),
|
||||
'zone': zone_val,
|
||||
'aisle': aisle_val,
|
||||
'rack': rack_val,
|
||||
'product_sku': sku_val,
|
||||
'quantity': quantity_val,
|
||||
'warehouse': warehouse_val,
|
||||
},
|
||||
action: 'manage',
|
||||
onSuccess: function() {
|
||||
@@ -189,6 +200,30 @@
|
||||
|
||||
}
|
||||
|
||||
function approve_current_stock() {
|
||||
bootbox.confirm({
|
||||
message: 'Approve this stock-in record?',
|
||||
buttons: { confirm: { label: 'Approve', className: 'btn-success' }, cancel: { label: 'Cancel', className: 'btn-secondary' } },
|
||||
callback: function(result) {
|
||||
if (!result) return;
|
||||
ajax_request({
|
||||
url: '<?php echo $server_url?>ics/api/engine/approve_stock.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'update',
|
||||
data: {
|
||||
id: '<?php echo $_GET["id"] ?? "";?>',
|
||||
warehouse: '<?php echo $_GET["wh"] ?? "";?>',
|
||||
type: 'in'
|
||||
},
|
||||
onSuccess: function() {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function retrieve_warehouse(type) {
|
||||
@@ -309,7 +344,7 @@
|
||||
|
||||
var data = res.output;
|
||||
|
||||
$('#warehouse').val('<?php echo $_GET["wh"];?>').attr('disabled', true);
|
||||
$('#warehouse').val('<?php echo $_GET["wh"] ?? "";?>').attr('disabled', true);
|
||||
|
||||
function populate_fields() {
|
||||
$.each(data, function(key, item) {
|
||||
@@ -336,6 +371,9 @@
|
||||
$('#product_sku, #quantity').prop('disabled', true);
|
||||
$('button[type=submit]').text('Update');
|
||||
$('button[type=reset]').hide();
|
||||
if (data.status == 0) {
|
||||
$('#approve_stock_btn').removeClass('d-none');
|
||||
}
|
||||
}
|
||||
|
||||
if (advanced) {
|
||||
@@ -465,4 +503,4 @@
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
<!-- Submit Button -->
|
||||
<div class="mb-3 col-lg-12">
|
||||
<button type="submit" class="btn btn-primary" onclick="manage_stock_out();">Remove Stock</button>
|
||||
<button type="button" class="btn btn-success ms-2 d-none" id="approve_stock_btn" onclick="approve_current_stock();">Approve</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -149,8 +150,11 @@
|
||||
}
|
||||
|
||||
function manage_stock_out() {
|
||||
var rack_val = $('#rack').val();
|
||||
var sku_val = $('#product_sku').attr('secondary') || $('#product_sku').val();
|
||||
var wh_val = $('#warehouse').val();
|
||||
|
||||
if (!advanced) {
|
||||
var rack_val = $('#rack').val();
|
||||
$('#zone').val(rack_val);
|
||||
$('#aisle').val(rack_val);
|
||||
}
|
||||
@@ -161,9 +165,12 @@
|
||||
checkRequired: 1,
|
||||
debugMode: 0,
|
||||
data: {
|
||||
'contact_id': $('#contact').attr('data-id'),
|
||||
'zone': $('#zone').val(),
|
||||
'aisle': $('#aisle').val(),
|
||||
'contact_id': $('#contact').attr('data-id'),
|
||||
'zone': advanced ? $('#zone').val() : rack_val,
|
||||
'aisle': advanced ? $('#aisle').val() : rack_val,
|
||||
'rack': rack_val,
|
||||
'product_sku': sku_val,
|
||||
'warehouse': wh_val,
|
||||
},
|
||||
action: 'manage',
|
||||
onSuccess: function() {
|
||||
@@ -172,6 +179,30 @@
|
||||
});
|
||||
}
|
||||
|
||||
function approve_current_stock() {
|
||||
bootbox.confirm({
|
||||
message: 'Approve this stock-out record?',
|
||||
buttons: { confirm: { label: 'Approve', className: 'btn-success' }, cancel: { label: 'Cancel', className: 'btn-secondary' } },
|
||||
callback: function(result) {
|
||||
if (!result) return;
|
||||
ajax_request({
|
||||
url: '<?php echo $server_url?>ics/api/engine/approve_stock.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'update',
|
||||
data: {
|
||||
id: '<?php echo $_GET["id"] ?? "";?>',
|
||||
warehouse: '<?php echo $_GET["wh"] ?? "";?>',
|
||||
type: 'out'
|
||||
},
|
||||
onSuccess: function() {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ── Step 1: Product selected → load active lots ───────────────────────
|
||||
function retrieve_active_lot() {
|
||||
@@ -242,7 +273,11 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
noLoading: true,
|
||||
data: { "type": 'from', "lot_number": $('#lot_number').val() },
|
||||
data: {
|
||||
"type": 'from',
|
||||
"product_sku": $('#product_sku').attr('secondary') || $('#product_sku').val(),
|
||||
"lot_number": $('#lot_number').val()
|
||||
},
|
||||
action: 'read',
|
||||
onSuccess: function(res) {
|
||||
var option = '<option value="">Select warehouse...</option>';
|
||||
@@ -264,6 +299,7 @@
|
||||
checkRequired: 0,
|
||||
noLoading: true,
|
||||
data: {
|
||||
"warehouse": $('#warehouse').val(),
|
||||
"type": 'from',
|
||||
"product_sku": $('#product_sku').attr('secondary') || $('#product_sku').val(),
|
||||
"lot_number": $('#lot_number').val(),
|
||||
@@ -289,6 +325,8 @@
|
||||
checkRequired: 0,
|
||||
noLoading: true,
|
||||
data: {
|
||||
"warehouse": $('#warehouse').val(),
|
||||
"zone": $('#zone').val(),
|
||||
"type": 'from',
|
||||
"product_sku": $('#product_sku').attr('secondary') || $('#product_sku').val(),
|
||||
"lot_number": $('#lot_number').val(),
|
||||
@@ -314,6 +352,9 @@
|
||||
checkRequired: 0,
|
||||
noLoading: true,
|
||||
data: {
|
||||
"warehouse": $('#warehouse').val(),
|
||||
"zone": $('#zone').val(),
|
||||
"aisle": $('#aisle').val(),
|
||||
"type": 'from',
|
||||
"product_sku": $('#product_sku').attr('secondary') || $('#product_sku').val(),
|
||||
"lot_number": $('#lot_number').val(),
|
||||
@@ -379,6 +420,9 @@
|
||||
$('#product_sku').attr('secondary', data.product_sku).prop('disabled', true);
|
||||
$('button[type=submit]').text('Update');
|
||||
$('button[type=reset]').hide();
|
||||
if (data.status == 0) {
|
||||
$('#approve_stock_btn').removeClass('d-none');
|
||||
}
|
||||
}
|
||||
|
||||
if (advanced) {
|
||||
@@ -462,4 +506,4 @@
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -131,6 +131,7 @@
|
||||
<!-- Submit -->
|
||||
<div class="mb-3 col-lg-12">
|
||||
<button type="submit" class="btn btn-primary" onclick="manage_stock_transfer();">Transfer Stock</button>
|
||||
<button type="button" class="btn btn-success ms-2 d-none" id="approve_stock_btn" onclick="approve_current_stock();">Approve</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -171,6 +172,7 @@
|
||||
if (advanced) {
|
||||
$('#group_zone_from, #group_zone_to').show();
|
||||
$('#group_aisle_from, #group_aisle_to').show();
|
||||
$('#zone_from, #zone_to, #aisle_from, #aisle_to').prop('required', true);
|
||||
$('#label_zone_from').text('From ' + label_zone);
|
||||
$('#label_zone_to').text('To ' + label_zone);
|
||||
$('#label_aisle_from').text('From ' + label_aisle);
|
||||
@@ -184,6 +186,7 @@
|
||||
} else {
|
||||
$('#group_zone_from, #group_zone_to').hide();
|
||||
$('#group_aisle_from, #group_aisle_to').hide();
|
||||
$('#zone_from, #zone_to, #aisle_from, #aisle_to').prop('required', false).removeClass('is-invalid is-valid');
|
||||
$('#label_rack_from').text('From ' + label_rack);
|
||||
$('#label_rack_to').text('To ' + label_rack);
|
||||
$('#rack_from, #rack_to').find('option:first').text('Please select ' + label_rack.toLowerCase());
|
||||
@@ -194,10 +197,12 @@
|
||||
// ── Submit ────────────────────────────────────────────────────────────────
|
||||
function manage_stock_transfer() {
|
||||
|
||||
var rack_from_val = $('#rack_from').val();
|
||||
var rack_to_val = $('#rack_to').val();
|
||||
var sku_val = $('#product_sku').attr('secondary') || $('#product_sku').val();
|
||||
|
||||
// Simple mode — mirror rack value to zone and aisle before submit
|
||||
if (!advanced) {
|
||||
var rack_from_val = $('#rack_from').val();
|
||||
var rack_to_val = $('#rack_to').val();
|
||||
$('#zone_from').val(rack_from_val);
|
||||
$('#aisle_from').val(rack_from_val);
|
||||
$('#zone_to').val(rack_to_val);
|
||||
@@ -208,7 +213,18 @@
|
||||
url: '<?php echo $server_url?>ics/api/engine/manage_stock_transfer.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 1,
|
||||
data: { 'contact_id': $('#contact').attr('data-id') },
|
||||
data: {
|
||||
'contact_id': $('#contact').attr('data-id'),
|
||||
'warehouse_from': $('#warehouse_from').val(),
|
||||
'warehouse_to': $('#warehouse_to').val(),
|
||||
'zone_from': advanced ? $('#zone_from').val() : rack_from_val,
|
||||
'aisle_from': advanced ? $('#aisle_from').val() : rack_from_val,
|
||||
'rack_from': rack_from_val,
|
||||
'zone_to': advanced ? $('#zone_to').val() : rack_to_val,
|
||||
'aisle_to': advanced ? $('#aisle_to').val() : rack_to_val,
|
||||
'rack_to': rack_to_val,
|
||||
'product_sku': sku_val,
|
||||
},
|
||||
action: 'manage',
|
||||
onSuccess: function() {
|
||||
window.location.href = '<?php echo $server_url?>ics/stock_transfer.php';
|
||||
@@ -216,6 +232,30 @@
|
||||
});
|
||||
}
|
||||
|
||||
function approve_current_stock() {
|
||||
bootbox.confirm({
|
||||
message: 'Approve this stock-transfer record?',
|
||||
buttons: { confirm: { label: 'Approve', className: 'btn-success' }, cancel: { label: 'Cancel', className: 'btn-secondary' } },
|
||||
callback: function(result) {
|
||||
if (!result) return;
|
||||
ajax_request({
|
||||
url: '<?php echo $server_url?>ics/api/engine/approve_stock.php',
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'update',
|
||||
data: {
|
||||
id: '<?php echo $_GET["id"] ?? "";?>',
|
||||
warehouse: '<?php echo $_GET["wh"] ?? "";?>',
|
||||
type: 'transfer'
|
||||
},
|
||||
onSuccess: function() {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ── Step 1: Product selected → load active lots + from-warehouses ─────────
|
||||
function retrieve_active_lot() {
|
||||
@@ -273,7 +313,11 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
noLoading: true,
|
||||
data: { 'type': type, 'lot_number': type === 'from' ? $('#lot_number').val() : '' },
|
||||
data: {
|
||||
'type': type,
|
||||
'product_sku': type === 'from' ? ($('#product_sku').attr('secondary') || $('#product_sku').val()) : '',
|
||||
'lot_number': type === 'from' ? $('#lot_number').val() : ''
|
||||
},
|
||||
action: 'read',
|
||||
onSuccess: function(res) {
|
||||
var option = '<option value="">Select warehouse...</option>';
|
||||
@@ -288,13 +332,16 @@
|
||||
|
||||
// ── Zone / Aisle / Rack loaders ───────────────────────────────────────────
|
||||
function retrieve_zone(type, callback) {
|
||||
var extra = {};
|
||||
var extra = {
|
||||
'warehouse_from': $('#warehouse_from').val(),
|
||||
'warehouse_to': $('#warehouse_to').val()
|
||||
};
|
||||
if (type === 'from') {
|
||||
extra = {
|
||||
extra = Object.assign(extra, {
|
||||
'product_sku': $('#product_sku').attr('secondary') || $('#product_sku').val(),
|
||||
'lot_number': $('#lot_number').val(),
|
||||
'serial_number': $('#serial_number').val()
|
||||
};
|
||||
});
|
||||
}
|
||||
return ajax_request({
|
||||
url: '<?php echo $server_url?>ics/api/engine/retrieve_zone.php',
|
||||
@@ -315,13 +362,18 @@
|
||||
}
|
||||
|
||||
function retrieve_aisle(type, callback) {
|
||||
var extra = {};
|
||||
var extra = {
|
||||
'warehouse_from': $('#warehouse_from').val(),
|
||||
'warehouse_to': $('#warehouse_to').val(),
|
||||
'zone_from': $('#zone_from').val(),
|
||||
'zone_to': $('#zone_to').val()
|
||||
};
|
||||
if (type === 'from') {
|
||||
extra = {
|
||||
extra = Object.assign(extra, {
|
||||
'product_sku': $('#product_sku').attr('secondary') || $('#product_sku').val(),
|
||||
'lot_number': $('#lot_number').val(),
|
||||
'serial_number': $('#serial_number').val()
|
||||
};
|
||||
});
|
||||
}
|
||||
return ajax_request({
|
||||
url: '<?php echo $server_url?>ics/api/engine/retrieve_aisle.php',
|
||||
@@ -342,13 +394,20 @@
|
||||
}
|
||||
|
||||
function retrieve_rack(type, callback) {
|
||||
var extra = {};
|
||||
var extra = {
|
||||
'warehouse_from': $('#warehouse_from').val(),
|
||||
'warehouse_to': $('#warehouse_to').val(),
|
||||
'zone_from': $('#zone_from').val(),
|
||||
'zone_to': $('#zone_to').val(),
|
||||
'aisle_from': $('#aisle_from').val(),
|
||||
'aisle_to': $('#aisle_to').val()
|
||||
};
|
||||
if (type === 'from') {
|
||||
extra = {
|
||||
extra = Object.assign(extra, {
|
||||
'product_sku': $('#product_sku').attr('secondary') || $('#product_sku').val(),
|
||||
'lot_number': $('#lot_number').val(),
|
||||
'serial_number': $('#serial_number').val()
|
||||
};
|
||||
});
|
||||
}
|
||||
return ajax_request({
|
||||
url: '<?php echo $server_url?>ics/api/engine/retrieve_rack.php',
|
||||
@@ -400,9 +459,17 @@
|
||||
$('#serial_number').html('<option value="' + (data.serial_number || '') + '">' + (data.serial_number || '—') + '</option>')
|
||||
.val(data.serial_number || '').prop('disabled', true);
|
||||
|
||||
$('#product_name').val(data.product_name);
|
||||
$('#product_sku').attr('secondary', data.product_sku).prop('disabled', true);
|
||||
|
||||
retrieve_warehouse('from').then(function() {
|
||||
return retrieve_warehouse('to');
|
||||
}).then(function() {
|
||||
$('select[name="warehouse"][role="from"]').val(from_wh).prop('disabled', true);
|
||||
$('select[name="warehouse"][role="to"]').val(to_wh).prop('disabled', true);
|
||||
|
||||
if (advanced) {
|
||||
// Full cascade for From
|
||||
$('select[name="warehouse"][role="from"]').val(from_wh).prop('disabled', true);
|
||||
retrieve_zone('from', function() {
|
||||
$('select[name="zone"][role="from"]').val(data.zone).prop('disabled', true);
|
||||
retrieve_aisle('from', function() {
|
||||
@@ -415,7 +482,6 @@
|
||||
});
|
||||
} else {
|
||||
// Simple mode — skip zone/aisle cascade, load rack directly
|
||||
$('select[name="warehouse"][role="from"]').val(from_wh).prop('disabled', true);
|
||||
retrieve_rack('from', function() {
|
||||
$('select[name="rack"][role="from"]').val(data.rack).prop('disabled', true);
|
||||
populate_to_side_simple(data, to_wh);
|
||||
@@ -432,16 +498,17 @@
|
||||
$('#contact').val(data.contact_name)
|
||||
.attr('secondary', data.contact_name)
|
||||
.attr('data-id', data.contact_id);
|
||||
$('#product_name').val(data.product_name);
|
||||
$('#product_sku').attr('secondary', data.product_sku).prop('disabled', true);
|
||||
$('button[type=submit]').text('Update');
|
||||
$('button[type=reset]').hide();
|
||||
if (data.status == 0) {
|
||||
$('#approve_stock_btn').removeClass('d-none');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function populate_to_side(data, to_wh) {
|
||||
$('select[name="warehouse"][role="to"]').val(to_wh).prop('disabled', true);
|
||||
retrieve_zone('to', function() {
|
||||
$('select[name="zone"][role="to"]').val(data.ref.zone).prop('disabled', true);
|
||||
retrieve_aisle('to', function() {
|
||||
@@ -454,7 +521,6 @@
|
||||
}
|
||||
|
||||
function populate_to_side_simple(data, to_wh) {
|
||||
$('select[name="warehouse"][role="to"]').val(to_wh).prop('disabled', true);
|
||||
retrieve_rack('to', function() {
|
||||
$('select[name="rack"][role="to"]').val(data.ref.rack).prop('disabled', true);
|
||||
});
|
||||
@@ -465,7 +531,9 @@
|
||||
$(async function() {
|
||||
try {
|
||||
await load_location_config(apply_location_labels);
|
||||
<?php if(empty($_GET['id'])){ ?>
|
||||
await retrieve_warehouse('to');
|
||||
<?php } ?>
|
||||
await retrieve_for_edit();
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
@@ -526,4 +594,4 @@
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+96
-28
@@ -31,10 +31,18 @@
|
||||
<div class="mb-3 col-lg-2">
|
||||
<input class="form-control" value='Warehouse' disabled>
|
||||
</div>
|
||||
<div class="mb-3 col-lg-4">
|
||||
<div class="mb-3 col-lg-2">
|
||||
<select name="warehouse" id="warehouse" class="form-select" required></select>
|
||||
</div>
|
||||
<div class="mb-3 col-lg-6">
|
||||
<div class="mb-3 col-lg-2">
|
||||
<input class="form-control" value='Source' disabled>
|
||||
</div>
|
||||
<div class="mb-3 col-lg-2">
|
||||
<select name="source" id="source" class="form-select">
|
||||
<option value="">All Sources</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3 col-lg-2">
|
||||
<button class='btn btn-secondary' onclick='retrieve_stock_in()'>Search</button>
|
||||
</div>
|
||||
|
||||
@@ -50,7 +58,8 @@
|
||||
<th>Product</th>
|
||||
<th>Lot Number</th>
|
||||
<th>Serial Number</th>
|
||||
<th>Quantity</th>
|
||||
<th style="text-align: right;">Quantity</th>
|
||||
<th>Source</th>
|
||||
<th class="th_loc_zone">Zone</th>
|
||||
<th class="th_loc_aisle">Aisle</th>
|
||||
<th class="th_loc_rack">Rack</th>
|
||||
@@ -103,6 +112,70 @@
|
||||
return `<td class="py-3">${item['rack'] || ''}</td>`;
|
||||
}
|
||||
|
||||
function escape_html(value) {
|
||||
return String(value ?? '').replace(/[&<>"']/g, function(char) {
|
||||
return {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
}[char];
|
||||
});
|
||||
}
|
||||
|
||||
function source_label(source) {
|
||||
source = source || '';
|
||||
if (!source) return 'Manual';
|
||||
return source.charAt(0).toUpperCase() + source.slice(1).replace(/_/g, ' ');
|
||||
}
|
||||
|
||||
function source_cell(source) {
|
||||
var label = escape_html(source_label(source));
|
||||
return source
|
||||
? `<span class="badge bg-info-subtle text-info">${label}</span>`
|
||||
: `<span class="badge bg-secondary-subtle text-secondary">${label}</span>`;
|
||||
}
|
||||
|
||||
function populate_source_filter(rows) {
|
||||
var current = $('#source').val() || '';
|
||||
var sources = {};
|
||||
|
||||
$.each(rows, function(_, item) {
|
||||
sources[item.source || '__manual__'] = item.source || '';
|
||||
});
|
||||
|
||||
var option = `<option value="">All Sources</option>`;
|
||||
$.each(Object.keys(sources).sort(), function(_, key) {
|
||||
var value = sources[key];
|
||||
var option_value = value || '__manual__';
|
||||
option += `<option value="${escape_html(option_value)}">${escape_html(source_label(value))}</option>`;
|
||||
});
|
||||
|
||||
$('#source').html(option).val(current);
|
||||
if ($('#source').val() !== current) $('#source').val('');
|
||||
}
|
||||
|
||||
function apply_source_filter() {
|
||||
var selected = $('#source').val() || '';
|
||||
var rows = alasql.tables.stock_in_all ? alasql.tables.stock_in_all.data : [];
|
||||
|
||||
if (!selected) {
|
||||
alasql.tables.stock_in.data = rows;
|
||||
} else {
|
||||
alasql.tables.stock_in.data = rows.filter(function(item) {
|
||||
var source = item.source || '';
|
||||
return selected === '__manual__' ? !source : source === selected;
|
||||
});
|
||||
}
|
||||
|
||||
var table_id = 'stock_in';
|
||||
var total_records = alasql.tables.stock_in.data.length;
|
||||
var page = generate_pagination(table_id, total_records);
|
||||
$(`table#${table_id} tfoot`).html(page);
|
||||
change_page_stock_in(1);
|
||||
}
|
||||
|
||||
function retrieve_stock_in() {
|
||||
|
||||
return ajax_request({
|
||||
@@ -114,22 +187,12 @@
|
||||
onSuccess: function(res) {
|
||||
|
||||
// Register the array as a table name
|
||||
alasql('CREATE TABLE IF NOT EXISTS stock_in_all');
|
||||
alasql('CREATE TABLE IF NOT EXISTS stock_in');
|
||||
alasql.tables.stock_in.data = res.output || [];
|
||||
alasql.tables.stock_in_all.data = res.output || [];
|
||||
|
||||
var total_records = alasql.tables.stock_in.data.length;
|
||||
|
||||
var table_id = 'stock_in';
|
||||
|
||||
var page = generate_pagination(table_id, total_records);
|
||||
$(`table#${table_id} tfoot`).html(page);
|
||||
|
||||
// dynamic function name
|
||||
if (typeof window[`change_page_${table_id}`] === "function") {
|
||||
window[`change_page_${table_id}`](1);
|
||||
} else {
|
||||
console.error(`Function change_page_${table_id} does not exist.`);
|
||||
}
|
||||
populate_source_filter(alasql.tables.stock_in_all.data);
|
||||
apply_source_filter();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -153,19 +216,19 @@
|
||||
<td class="py-3">${item["product_sku"]}: ${item['product_name']}</td>
|
||||
<td class="py-3">${item['lot_number'] || '<span class="text-muted">—</span>'}</td>
|
||||
<td class="py-3">${item['serial_number'] || '<span class="text-muted">—</span>'}</td>
|
||||
<td class="py-3">${item['quantity']}</td>
|
||||
<td class="py-3">
|
||||
<div class="d-flex justify-content-end align-items-baseline gap-1">
|
||||
<span>${format_number(item['quantity'], 2)}</span>
|
||||
<span class="text-muted small" style="min-width:28px;">${item['uom'] || ''}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3">${source_cell(item['source'])}</td>
|
||||
${location_cells(item)}
|
||||
<td class="py-3">
|
||||
${item['status'] == 1 ? '<span class="badge bg-success">Approved</span>' : '<span class="badge bg-warning text-dark">Draft</span>'}
|
||||
</td>
|
||||
<td class="py-3">
|
||||
<a href="<?php echo $server_url?>ics/manage_stock_in.php?id=${item['id']}&wh=${warehouse}" class=""><i class="ti ti-eye fs-5"></i></a>
|
||||
${item['status'] == 0
|
||||
? (auto_approve
|
||||
? '<button class="btn btn-sm btn-outline-secondary ms-2" disabled title="Auto-approved on save — no manual approval needed"><i class=\"ti ti-check\"></i></button>'
|
||||
: '<button class="btn btn-sm btn-outline-success ms-2" onclick=\"approve_stock('+item['id']+', '+item['warehouse_id']+', \'in\')\" title="Approve"><i class=\"ti ti-check\"></i></button>'
|
||||
)
|
||||
: ''}
|
||||
<a href="javascript:void(0);" class="link-danger"
|
||||
onclick="delete_stock_in($(this),${item['id']})">
|
||||
<i class="ti ti-trash ms-2 fs-5"></i>
|
||||
@@ -225,6 +288,9 @@
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('change', '#source', apply_source_filter);
|
||||
$(document).on('change', '#warehouse', retrieve_stock_in);
|
||||
|
||||
// ── Stock approval ────────────────────────────────────────────────────────
|
||||
var auto_approve = false; // set from company_setting on load
|
||||
@@ -258,11 +324,13 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'update',
|
||||
id: id,
|
||||
warehouse: warehouse_id,
|
||||
type: type,
|
||||
data: {
|
||||
id: id,
|
||||
warehouse: warehouse_id,
|
||||
type: type
|
||||
},
|
||||
onSuccess: function(res) {
|
||||
retrieve_stock_list();
|
||||
retrieve_stock_in();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+96
-28
@@ -31,10 +31,18 @@
|
||||
<div class="mb-3 col-lg-2">
|
||||
<input class="form-control" value='Warehouse' disabled>
|
||||
</div>
|
||||
<div class="mb-3 col-lg-4">
|
||||
<div class="mb-3 col-lg-2">
|
||||
<select name="warehouse" id="warehouse" class="form-select" required></select>
|
||||
</div>
|
||||
<div class="mb-3 col-lg-6">
|
||||
<div class="mb-3 col-lg-2">
|
||||
<input class="form-control" value='Source' disabled>
|
||||
</div>
|
||||
<div class="mb-3 col-lg-2">
|
||||
<select name="source" id="source" class="form-select">
|
||||
<option value="">All Sources</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3 col-lg-2">
|
||||
<button class='btn btn-secondary' onclick='retrieve_stock_out()'>Search</button>
|
||||
</div>
|
||||
|
||||
@@ -50,7 +58,8 @@
|
||||
<th>Product</th>
|
||||
<th>Lot Number</th>
|
||||
<th>Serial Number</th>
|
||||
<th>Quantity</th>
|
||||
<th style="text-align: right;">Quantity</th>
|
||||
<th>Source</th>
|
||||
<th class="th_loc_zone">Zone</th>
|
||||
<th class="th_loc_aisle">Aisle</th>
|
||||
<th class="th_loc_rack">Rack</th>
|
||||
@@ -103,6 +112,70 @@
|
||||
return `<td class="py-3">${item['rack'] || ''}</td>`;
|
||||
}
|
||||
|
||||
function escape_html(value) {
|
||||
return String(value ?? '').replace(/[&<>"']/g, function(char) {
|
||||
return {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
}[char];
|
||||
});
|
||||
}
|
||||
|
||||
function source_label(source) {
|
||||
source = source || '';
|
||||
if (!source) return 'Manual';
|
||||
return source.charAt(0).toUpperCase() + source.slice(1).replace(/_/g, ' ');
|
||||
}
|
||||
|
||||
function source_cell(source) {
|
||||
var label = escape_html(source_label(source));
|
||||
return source
|
||||
? `<span class="badge bg-info-subtle text-info">${label}</span>`
|
||||
: `<span class="badge bg-secondary-subtle text-secondary">${label}</span>`;
|
||||
}
|
||||
|
||||
function populate_source_filter(rows) {
|
||||
var current = $('#source').val() || '';
|
||||
var sources = {};
|
||||
|
||||
$.each(rows, function(_, item) {
|
||||
sources[item.source || '__manual__'] = item.source || '';
|
||||
});
|
||||
|
||||
var option = `<option value="">All Sources</option>`;
|
||||
$.each(Object.keys(sources).sort(), function(_, key) {
|
||||
var value = sources[key];
|
||||
var option_value = value || '__manual__';
|
||||
option += `<option value="${escape_html(option_value)}">${escape_html(source_label(value))}</option>`;
|
||||
});
|
||||
|
||||
$('#source').html(option).val(current);
|
||||
if ($('#source').val() !== current) $('#source').val('');
|
||||
}
|
||||
|
||||
function apply_source_filter() {
|
||||
var selected = $('#source').val() || '';
|
||||
var rows = alasql.tables.stock_out_all ? alasql.tables.stock_out_all.data : [];
|
||||
|
||||
if (!selected) {
|
||||
alasql.tables.stock_out.data = rows;
|
||||
} else {
|
||||
alasql.tables.stock_out.data = rows.filter(function(item) {
|
||||
var source = item.source || '';
|
||||
return selected === '__manual__' ? !source : source === selected;
|
||||
});
|
||||
}
|
||||
|
||||
var table_id = 'stock_out';
|
||||
var total_records = alasql.tables.stock_out.data.length;
|
||||
var page = generate_pagination(table_id, total_records);
|
||||
$(`table#${table_id} tfoot`).html(page);
|
||||
change_page_stock_out(1);
|
||||
}
|
||||
|
||||
function retrieve_stock_out() {
|
||||
|
||||
return ajax_request({
|
||||
@@ -114,22 +187,12 @@
|
||||
onSuccess: function(res) {
|
||||
|
||||
// Register the array as a table name
|
||||
alasql('CREATE TABLE IF NOT EXISTS stock_out_all');
|
||||
alasql('CREATE TABLE IF NOT EXISTS stock_out');
|
||||
alasql.tables.stock_out.data = res.output || [];
|
||||
alasql.tables.stock_out_all.data = res.output || [];
|
||||
|
||||
var total_records = alasql.tables.stock_out.data.length;
|
||||
|
||||
var table_id = 'stock_out';
|
||||
|
||||
var page = generate_pagination(table_id, total_records);
|
||||
$(`table#${table_id} tfoot`).html(page);
|
||||
|
||||
// dynamic function name
|
||||
if (typeof window[`change_page_${table_id}`] === "function") {
|
||||
window[`change_page_${table_id}`](1);
|
||||
} else {
|
||||
console.error(`Function change_page_${table_id} does not exist.`);
|
||||
}
|
||||
populate_source_filter(alasql.tables.stock_out_all.data);
|
||||
apply_source_filter();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -153,19 +216,19 @@
|
||||
<td class="py-3">${item["product_sku"]}: ${item['product_name']}</td>
|
||||
<td class="py-3">${item['lot_number'] || '<span class="text-muted">—</span>'}</td>
|
||||
<td class="py-3">${item['serial_number'] || '<span class="text-muted">—</span>'}</td>
|
||||
<td class="py-3">${item['quantity']}</td>
|
||||
<td class="py-3">
|
||||
<div class="d-flex justify-content-end align-items-baseline gap-1">
|
||||
<span>${format_number(item['quantity'], 2)}</span>
|
||||
<span class="text-muted small" style="min-width:28px;">${item['uom'] || ''}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3">${source_cell(item['source'])}</td>
|
||||
${location_cells(item)}
|
||||
<td class="py-3">
|
||||
${item['status'] == 1 ? '<span class="badge bg-success">Approved</span>' : '<span class="badge bg-warning text-dark">Draft</span>'}
|
||||
</td>
|
||||
<td class="py-3">
|
||||
<a href="<?php echo $server_url?>ics/manage_stock_out.php?id=${item['id']}&wh=${warehouse}" class=""><i class="ti ti-eye fs-5"></i></a>
|
||||
${item['status'] == 0
|
||||
? (auto_approve
|
||||
? '<button class="btn btn-sm btn-outline-secondary ms-2" disabled title="Auto-approved on save — no manual approval needed"><i class=\"ti ti-check\"></i></button>'
|
||||
: '<button class="btn btn-sm btn-outline-success ms-2" onclick=\"approve_stock('+item['id']+', '+item['warehouse_id']+', \'out\')\" title="Approve"><i class=\"ti ti-check\"></i></button>'
|
||||
)
|
||||
: ''}
|
||||
<a href="javascript:void(0);" class="link-danger"
|
||||
onclick="delete_stock_out($(this),${item['id']})">
|
||||
<i class="ti ti-trash ms-2 fs-5"></i>
|
||||
@@ -225,6 +288,9 @@
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('change', '#source', apply_source_filter);
|
||||
$(document).on('change', '#warehouse', retrieve_stock_out);
|
||||
|
||||
// ── Stock approval ────────────────────────────────────────────────────────
|
||||
var auto_approve = false; // set from company_setting on load
|
||||
@@ -258,11 +324,13 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'update',
|
||||
id: id,
|
||||
warehouse: warehouse_id,
|
||||
type: type,
|
||||
data: {
|
||||
id: id,
|
||||
warehouse: warehouse_id,
|
||||
type: type
|
||||
},
|
||||
onSuccess: function(res) {
|
||||
retrieve_stock_list();
|
||||
retrieve_stock_out();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+15
-12
@@ -48,7 +48,7 @@
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Product</th>
|
||||
<th>Quantity</th>
|
||||
<th style="text-align: right;">Quantity</th>
|
||||
<th class="th_loc_zone">Zone</th>
|
||||
<th class="th_loc_aisle">Aisle</th>
|
||||
<th class="th_loc_rack">Rack</th>
|
||||
@@ -149,19 +149,18 @@
|
||||
body += `<tr>
|
||||
<td class="py-3">${format_date(item["date"])}</td>
|
||||
<td class="py-3">${item["product_sku"]}: ${item['product_name']}</td>
|
||||
<td class="py-3">${item['quantity']}</td>
|
||||
<td class="py-3">
|
||||
<div class="d-flex justify-content-end align-items-baseline gap-1">
|
||||
<span>${format_number(item['quantity'], 2)}</span>
|
||||
<span class="text-muted small" style="min-width:28px;">${item['uom'] || ''}</span>
|
||||
</div>
|
||||
</td>
|
||||
${location_cells(item)}
|
||||
<td class="py-3">
|
||||
${item['status'] == 1 ? '<span class="badge bg-success">Approved</span>' : '<span class="badge bg-warning text-dark">Draft</span>'}
|
||||
</td>
|
||||
<td class="py-3">
|
||||
<a href="<?php echo $server_url?>ics/manage_stock_transfer.php?id=${item['id']}&wh=${warehouse}" class=""><i class="ti ti-eye fs-5"></i></a>
|
||||
${item['status'] == 0
|
||||
? (auto_approve
|
||||
? '<button class="btn btn-sm btn-outline-secondary ms-2" disabled title="Auto-approved on save — no manual approval needed"><i class=\"ti ti-check\"></i></button>'
|
||||
: '<button class="btn btn-sm btn-outline-success ms-2" onclick=\"approve_stock('+item['id']+', '+item['warehouse_id']+', \'transfer\')\" title="Approve"><i class=\"ti ti-check\"></i></button>'
|
||||
)
|
||||
: ''}
|
||||
<a href="javascript:void(0);" class="link-danger"
|
||||
onclick="delete_stock_transfer($(this),${item['id']})">
|
||||
<i class="ti ti-trash ms-2 fs-5"></i>
|
||||
@@ -223,6 +222,8 @@
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('change', '#warehouse', retrieve_stock_transfer);
|
||||
|
||||
// ── Stock approval ────────────────────────────────────────────────────────
|
||||
var auto_approve = false; // set from company_setting on load
|
||||
@@ -256,11 +257,13 @@
|
||||
autoPrepare: true,
|
||||
checkRequired: 0,
|
||||
action: 'update',
|
||||
id: id,
|
||||
warehouse: warehouse_id,
|
||||
type: type,
|
||||
data: {
|
||||
id: id,
|
||||
warehouse: warehouse_id,
|
||||
type: type
|
||||
},
|
||||
onSuccess: function(res) {
|
||||
retrieve_stock_list();
|
||||
retrieve_stock_transfer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user