implement JS password scoring, td_stock approve logicc
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
exit(json_encode($answer));
|
||||
}
|
||||
|
||||
$report = new ReportManager($pdo2, $company_id);
|
||||
$report = new ReportManager($pdo2, $company_id, $db_database);
|
||||
$answer['output'] = $report->getRackLog($rack_id);
|
||||
$answer['success'] = 1;
|
||||
exit(json_encode($answer));
|
||||
|
||||
@@ -229,14 +229,14 @@
|
||||
// ── Render both tables from filtered data ────────────────────────────
|
||||
function render_tables() {
|
||||
|
||||
var kw = search_term.toLowerCase();
|
||||
var kw = search_term;
|
||||
var fs = filter_status;
|
||||
|
||||
var filtered = all_items.filter(function(item) {
|
||||
var match_search = !kw ||
|
||||
item.product_name.toLowerCase().includes(kw) ||
|
||||
item.product_sku.toLowerCase().includes(kw) ||
|
||||
(item.lot_number || '').toLowerCase().includes(kw);
|
||||
item.product_name || ''.includes(kw) ||
|
||||
item.product_sku || ''.includes(kw) ||
|
||||
item.lot_number || ''.includes(kw);
|
||||
var match_status = !fs || item.status === fs;
|
||||
return match_search && match_status;
|
||||
});
|
||||
|
||||
@@ -472,8 +472,7 @@
|
||||
|
||||
$('#rackLogModalLabel').text('Rack Log — ' + label);
|
||||
$('#rack_log_body').html('<tr><td colspan="4" class="text-center py-4 text-muted">Loading...</td></tr>');
|
||||
var modal = new bootstrap.Modal(document.getElementById('rackLogModal'));
|
||||
modal.show();
|
||||
$('#rackLogModal').modal('show');
|
||||
|
||||
ajax_request({
|
||||
url: "<?php echo $server_url?>reports/api/engine_report/rack_log.php",
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
<th>Expiry Date</th>
|
||||
<th>Days Remaining</th>
|
||||
<th>Balance</th>
|
||||
<th>Active</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
@@ -259,6 +260,9 @@
|
||||
<td class="py-3">${item.expiry_date || '<span class="text-muted">—</span>'}</td>
|
||||
<td class="py-3">${days_lbl}</td>
|
||||
<td class="py-3">${Number(item.balance).toLocaleString()}</td>
|
||||
<td class="py-3">${item.is_active == 1
|
||||
? '<span class="badge bg-success">Active</span>'
|
||||
: '<span class="badge bg-secondary">Inactive</span>'}</td>
|
||||
<td class="py-3">${status_badge[item.status] || ''}</td>
|
||||
<td class="py-3">
|
||||
<a href="javascript:;" onclick="view_lot_log('${item.product_sku}','${item.lot_number}')">
|
||||
|
||||
@@ -28,6 +28,32 @@
|
||||
<button class="btn btn-primary btn-sm text-nowrap" onclick="do_search();">
|
||||
<i class="ti ti-search"></i> Search
|
||||
</button>
|
||||
<div class="dropdown">
|
||||
<a href="#" role="button" class="btn btn-outline-secondary btn-sm text-nowrap" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="ti ti-download me-1"></i> Export
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end p-0" style="min-width: 160px;">
|
||||
<div>
|
||||
<div class="d-flex gap-3 align-items-center border-dashed border-bottom px-3 py-3">
|
||||
<i class="ti ti-download"></i>
|
||||
<div>
|
||||
<h4 class="mb-0 small">Export</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3 d-flex flex-column gap-1 small lh-lg">
|
||||
<a href="javascript:;" onclick="export_report('csv')">
|
||||
<span><i class="ti ti-file-type-csv me-2"></i>CSV</span>
|
||||
</a>
|
||||
<a href="javascript:;" onclick="export_report('xlsx')">
|
||||
<span><i class="ti ti-file-type-xls me-2"></i>Excel</span>
|
||||
</a>
|
||||
<a href="javascript:;" onclick="export_report('pdf')">
|
||||
<span><i class="ti ti-file-type-pdf me-2"></i>PDF</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -194,6 +220,7 @@
|
||||
sku_queue = [];
|
||||
sku_index = 0;
|
||||
is_loading = false;
|
||||
export_data = [];
|
||||
search_params = { warehouse_id: warehouse_id, from_month: from_month, to_month: to_month };
|
||||
|
||||
// Reset UI
|
||||
@@ -295,9 +322,31 @@
|
||||
|
||||
// ── Render one SKU group into the table ───────────────────────────────
|
||||
function append_sku_group(d) {
|
||||
var bf = d.brought_forward;
|
||||
var bf = d.brought_forward;
|
||||
var rows = d.rows;
|
||||
|
||||
// Populate export_data — brought forward row first, then transactions
|
||||
export_data.push({
|
||||
sku: d.sku, product: d.product_name, date: 'Brought Forward', type: '',
|
||||
lot: '', location: '', contact: '',
|
||||
stock_in: bf.in > 0 ? bf.in : '', stock_out: bf.out > 0 ? bf.out : '',
|
||||
running_total: bf.balance,
|
||||
});
|
||||
$.each(rows, function(i, row) {
|
||||
export_data.push({
|
||||
sku: row.product_sku,
|
||||
product: d.product_name,
|
||||
date: row.date,
|
||||
type: row.type,
|
||||
lot: row.lot_number || '',
|
||||
location: row.zone + '-' + row.aisle + '-' + row.rack,
|
||||
contact: row.contact_name || '',
|
||||
stock_in: row.stock_in > 0 ? row.stock_in : '',
|
||||
stock_out: row.stock_out > 0 ? row.stock_out : '',
|
||||
running_total: row.running_total,
|
||||
});
|
||||
});
|
||||
|
||||
// SKU header row
|
||||
var header = `<tr class="table-secondary">
|
||||
<td colspan="9" class="py-2 fw-semibold">
|
||||
@@ -364,11 +413,77 @@
|
||||
}
|
||||
|
||||
|
||||
// ── Boot ──────────────────────────────────────────────────────────────
|
||||
// ── Export ───────────────────────────────────────────────────────────
|
||||
// export_data holds all rows accumulated across all loaded SKU groups.
|
||||
// It is populated by append_sku_group() alongside the table render.
|
||||
var export_data = [];
|
||||
|
||||
function export_report(format) {
|
||||
|
||||
if (export_data.length === 0) {
|
||||
alert('No data to export. Please search first.');
|
||||
return;
|
||||
}
|
||||
|
||||
var warehouse = $('#warehouse option:selected').text();
|
||||
var from = $('#from_month').val();
|
||||
var to = $('#to_month').val();
|
||||
var filename = 'stock_movement_' + warehouse + '_' + from + '_' + to;
|
||||
|
||||
if (format === 'csv') {
|
||||
alasql('SELECT * INTO CSV("' + filename + '.csv", {headers:true}) FROM ?', [export_data]);
|
||||
|
||||
} else if (format === 'xlsx') {
|
||||
alasql('SELECT * INTO XLSX("' + filename + '.xlsx", {headers:true}) FROM ?', [export_data]);
|
||||
|
||||
} else if (format === 'pdf') {
|
||||
var { jsPDF } = window.jspdf;
|
||||
var doc = new jsPDF({ orientation: 'landscape' });
|
||||
|
||||
doc.setFontSize(12);
|
||||
doc.text('Stock Movement — ' + warehouse + ' (' + from + ' to ' + to + ')', 14, 15);
|
||||
|
||||
var headers = [['SKU', 'Product', 'Date', 'Type', 'Lot', 'Location', 'Contact', 'Stock In', 'Stock Out', 'Running Total']];
|
||||
var rows = export_data.map(function(r) {
|
||||
return [
|
||||
r.sku || '',
|
||||
r.product || '',
|
||||
r.date || '',
|
||||
r.type || '',
|
||||
r.lot || '',
|
||||
r.location || '',
|
||||
r.contact || '',
|
||||
r.stock_in || '',
|
||||
r.stock_out || '',
|
||||
r.running_total || '',
|
||||
];
|
||||
});
|
||||
|
||||
doc.autoTable({
|
||||
head: headers,
|
||||
body: rows,
|
||||
startY: 22,
|
||||
styles: { fontSize: 7 },
|
||||
headStyles: { fillColor: [41, 128, 185] },
|
||||
});
|
||||
|
||||
doc.save(filename + '.pdf');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$(async function() {
|
||||
try { await retrieve_warehouse(); } catch(e) { console.log(e); }
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- SheetJS — required by AlaSQL for Excel (.xlsx) export -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
|
||||
|
||||
<!-- jsPDF + autoTable — for PDF export on stock movement report -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.2/jspdf.plugin.autotable.min.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user