update scale setting
This commit is contained in:
parent
d230ce890d
commit
d5e994ab87
184
index.php
184
index.php
@ -501,20 +501,49 @@ if (isset($_GET['action']) || isset($_POST['action'])) {
|
|||||||
|
|
||||||
if ($action === 'pos_get_item_by_sku') {
|
if ($action === 'pos_get_item_by_sku') {
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
$sku = $_GET['sku'] ?? '';
|
$sku = trim((string)($_GET['sku'] ?? ''));
|
||||||
if (!$sku) { echo json_encode(null); exit; }
|
if ($sku === '') { echo json_encode(null); exit; }
|
||||||
|
|
||||||
|
$weightBarcode = parseWeightBarcode($sku);
|
||||||
|
$lookupSku = $weightBarcode['item_code'] ?? $sku;
|
||||||
|
|
||||||
$oid = current_outlet_id();
|
$oid = current_outlet_id();
|
||||||
$stmt = db()->prepare("SELECT * FROM stock_items WHERE sku = ? AND outlet_id = ? LIMIT 1");
|
$stmt = db()->prepare("SELECT * FROM stock_items WHERE sku = ? AND outlet_id = ? LIMIT 1");
|
||||||
$stmt->execute([$sku, $oid]);
|
$stmt->execute([$lookupSku, $oid]);
|
||||||
$p = $stmt->fetch(PDO::FETCH_ASSOC);
|
$p = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if ($p) {
|
if ($p) {
|
||||||
$p['original_price'] = (float)$p['sale_price'];
|
$p['original_price'] = (float)$p['sale_price'];
|
||||||
$p['sale_price'] = getPromotionalPrice($p);
|
$p['sale_price'] = getPromotionalPrice($p);
|
||||||
|
$p['price'] = (float)$p['sale_price'];
|
||||||
$p['nameEn'] = $p['name_en'];
|
$p['nameEn'] = $p['name_en'];
|
||||||
$p['nameAr'] = $p['name_ar'];
|
$p['nameAr'] = $p['name_ar'];
|
||||||
$p['vatRate'] = $p['vat_rate'];
|
$p['vatRate'] = $p['vat_rate'];
|
||||||
|
|
||||||
|
if ($weightBarcode) {
|
||||||
|
$qty = 0.0;
|
||||||
|
if ($weightBarcode['mode'] === 'price') {
|
||||||
|
if ((float)$p['sale_price'] <= 0) {
|
||||||
|
echo json_encode(['error' => 'This item cannot use price-based scale barcodes because its sale price is zero.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$qty = round(((float)$weightBarcode['value']) / (float)$p['sale_price'], 3);
|
||||||
|
} else {
|
||||||
|
$qty = round((float)$weightBarcode['value'], 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($qty <= 0) {
|
||||||
|
echo json_encode(['error' => 'The weighing scale barcode value is invalid.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$p['qty'] = $qty;
|
||||||
|
$p['is_scale_barcode'] = true;
|
||||||
|
$p['scale_barcode_mode'] = $weightBarcode['mode'];
|
||||||
|
$p['scale_barcode_value'] = (float)$weightBarcode['value'];
|
||||||
|
$p['scanned_barcode'] = $sku;
|
||||||
|
}
|
||||||
|
|
||||||
echo json_encode($p);
|
echo json_encode($p);
|
||||||
} else {
|
} else {
|
||||||
echo json_encode(null);
|
echo json_encode(null);
|
||||||
@ -826,6 +855,71 @@ if (!isset($_SESSION['user_id'])) {
|
|||||||
$message = $_SESSION['message'] ?? '';
|
$message = $_SESSION['message'] ?? '';
|
||||||
unset($_SESSION['message']);
|
unset($_SESSION['message']);
|
||||||
|
|
||||||
|
function getSettingValue(string $key, ?string $default = null): ?string {
|
||||||
|
static $cache = [];
|
||||||
|
if (array_key_exists($key, $cache)) return $cache[$key];
|
||||||
|
try {
|
||||||
|
$stmt = db()->prepare("SELECT value FROM settings WHERE `key` = ? LIMIT 1");
|
||||||
|
$stmt->execute([$key]);
|
||||||
|
$value = $stmt->fetchColumn();
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$value = false;
|
||||||
|
}
|
||||||
|
if ($value === false || $value === null || $value === '') $value = $default;
|
||||||
|
$cache[$key] = $value;
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWeightBarcodeConfig(): array {
|
||||||
|
$prefixStart = (int)(getSettingValue('weight_barcode_prefix_start', '20') ?? '20');
|
||||||
|
$prefixEnd = (int)(getSettingValue('weight_barcode_prefix_end', '29') ?? '29');
|
||||||
|
if ($prefixStart < 20 || $prefixStart > 29) $prefixStart = 20;
|
||||||
|
if ($prefixEnd < 20 || $prefixEnd > 29) $prefixEnd = 29;
|
||||||
|
if ($prefixStart > $prefixEnd) {
|
||||||
|
[$prefixStart, $prefixEnd] = [$prefixEnd, $prefixStart];
|
||||||
|
}
|
||||||
|
$mode = strtolower((string)(getSettingValue('weight_barcode_mode', 'weight') ?? 'weight'));
|
||||||
|
if (!in_array($mode, ['weight', 'price'], true)) $mode = 'weight';
|
||||||
|
return [
|
||||||
|
'prefix_start' => $prefixStart,
|
||||||
|
'prefix_end' => $prefixEnd,
|
||||||
|
'mode' => $mode,
|
||||||
|
'value_divisor' => 1000,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function isWeightBarcode(string $barcode): bool {
|
||||||
|
$barcode = trim($barcode);
|
||||||
|
if (!preg_match('/^\d{13}$/', $barcode)) return false;
|
||||||
|
$config = getWeightBarcodeConfig();
|
||||||
|
$prefix = (int)substr($barcode, 0, 2);
|
||||||
|
return $prefix >= $config['prefix_start'] && $prefix <= $config['prefix_end'];
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseWeightBarcode(string $barcode): ?array {
|
||||||
|
$barcode = trim($barcode);
|
||||||
|
if (!isWeightBarcode($barcode)) return null;
|
||||||
|
$config = getWeightBarcodeConfig();
|
||||||
|
$rawValue = (int)substr($barcode, 7, 5);
|
||||||
|
return [
|
||||||
|
'full_barcode' => $barcode,
|
||||||
|
'prefix' => substr($barcode, 0, 2),
|
||||||
|
'item_code' => substr($barcode, 2, 5),
|
||||||
|
'raw_value' => $rawValue,
|
||||||
|
'value' => $rawValue / (float)$config['value_divisor'],
|
||||||
|
'mode' => $config['mode'],
|
||||||
|
'check_digit' => substr($barcode, 12, 1),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateItemSkuBarcode(string $sku): ?string {
|
||||||
|
$sku = trim($sku);
|
||||||
|
if ($sku === '') return null;
|
||||||
|
if (!isWeightBarcode($sku)) return null;
|
||||||
|
$config = getWeightBarcodeConfig();
|
||||||
|
return "This barcode is reserved for weighing scale scans. 13-digit barcodes starting with {$config['prefix_start']}-{$config['prefix_end']} cannot be saved as item barcodes; please save the 5-digit scale item code instead.";
|
||||||
|
}
|
||||||
|
|
||||||
function redirectWithMessage($msg, $url = null) {
|
function redirectWithMessage($msg, $url = null) {
|
||||||
if (!$url) {
|
if (!$url) {
|
||||||
$url = $_SERVER['REQUEST_URI'];
|
$url = $_SERVER['REQUEST_URI'];
|
||||||
@ -892,7 +986,10 @@ function getPromotionalPrice($item) {
|
|||||||
$category_id = (int)$_POST['category_id'] ?: null;
|
$category_id = (int)$_POST['category_id'] ?: null;
|
||||||
$unit_id = (int)$_POST['unit_id'] ?: null;
|
$unit_id = (int)$_POST['unit_id'] ?: null;
|
||||||
$supplier_id = (int)$_POST['supplier_id'] ?: null;
|
$supplier_id = (int)$_POST['supplier_id'] ?: null;
|
||||||
$sku = $_POST['sku'] ?? '';
|
$sku = trim((string)($_POST['sku'] ?? ''));
|
||||||
|
if ($sku_error = validateItemSkuBarcode($sku)) {
|
||||||
|
redirectWithMessage($sku_error, 'index.php?page=items');
|
||||||
|
}
|
||||||
$sale_price = (float)($_POST['sale_price'] ?? 0);
|
$sale_price = (float)($_POST['sale_price'] ?? 0);
|
||||||
$purchase_price = (float)($_POST['purchase_price'] ?? 0);
|
$purchase_price = (float)($_POST['purchase_price'] ?? 0);
|
||||||
$stock_quantity = (float)($_POST['stock_quantity'] ?? 0);
|
$stock_quantity = (float)($_POST['stock_quantity'] ?? 0);
|
||||||
@ -925,7 +1022,10 @@ function getPromotionalPrice($item) {
|
|||||||
$category_id = (int)$_POST['category_id'] ?: null;
|
$category_id = (int)$_POST['category_id'] ?: null;
|
||||||
$unit_id = (int)$_POST['unit_id'] ?: null;
|
$unit_id = (int)$_POST['unit_id'] ?: null;
|
||||||
$supplier_id = (int)$_POST['supplier_id'] ?: null;
|
$supplier_id = (int)$_POST['supplier_id'] ?: null;
|
||||||
$sku = $_POST['sku'] ?? '';
|
$sku = trim((string)($_POST['sku'] ?? ''));
|
||||||
|
if ($sku_error = validateItemSkuBarcode($sku)) {
|
||||||
|
redirectWithMessage($sku_error, 'index.php?page=items');
|
||||||
|
}
|
||||||
$sale_price = (float)($_POST['sale_price'] ?? 0);
|
$sale_price = (float)($_POST['sale_price'] ?? 0);
|
||||||
$purchase_price = (float)($_POST['purchase_price'] ?? 0);
|
$purchase_price = (float)($_POST['purchase_price'] ?? 0);
|
||||||
$stock_quantity = (float)($_POST['stock_quantity'] ?? 0);
|
$stock_quantity = (float)($_POST['stock_quantity'] ?? 0);
|
||||||
@ -1449,6 +1549,8 @@ function getPromotionalPrice($item) {
|
|||||||
# --- Unified Import Logic (Excel & CSV) ---
|
# --- Unified Import Logic (Excel & CSV) ---
|
||||||
if (isset($_POST['import_items'])) {
|
if (isset($_POST['import_items'])) {
|
||||||
error_log("Import items triggered.");
|
error_log("Import items triggered.");
|
||||||
|
$count = 0;
|
||||||
|
$skipped = 0;
|
||||||
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === 0) {
|
||||||
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
$tmpPath = $_FILES['excel_file']['tmp_name'];
|
||||||
$rows = [];
|
$rows = [];
|
||||||
@ -1468,6 +1570,10 @@ function getPromotionalPrice($item) {
|
|||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
if (empty($row[0])) continue;
|
if (empty($row[0])) continue;
|
||||||
$sku = trim((string)$row[0]);
|
$sku = trim((string)$row[0]);
|
||||||
|
if ($sku_error = validateItemSkuBarcode($sku)) {
|
||||||
|
$skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$name_en = trim((string)($row[1] ?? ''));
|
$name_en = trim((string)($row[1] ?? ''));
|
||||||
$name_ar = trim((string)($row[2] ?? ''));
|
$name_ar = trim((string)($row[2] ?? ''));
|
||||||
$sale_price = (float)($row[3] ?? 0);
|
$sale_price = (float)($row[3] ?? 0);
|
||||||
@ -1491,7 +1597,12 @@ function getPromotionalPrice($item) {
|
|||||||
}
|
}
|
||||||
$count++;
|
$count++;
|
||||||
}
|
}
|
||||||
redirectWithMessage("Import items completed! $count processed.", "index.php?page=items");
|
$weightConfig = getWeightBarcodeConfig();
|
||||||
|
$summary = "Import items completed! $count processed.";
|
||||||
|
if ($skipped > 0) {
|
||||||
|
$summary .= " $skipped skipped because 13-digit barcodes starting with {$weightConfig['prefix_start']}-{$weightConfig['prefix_end']} are reserved for weighing scale barcodes.";
|
||||||
|
}
|
||||||
|
redirectWithMessage($summary, "index.php?page=items");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2437,7 +2548,19 @@ if (isset($_POST['add_hr_department'])) {
|
|||||||
if (can('settings_view')) {
|
if (can('settings_view')) {
|
||||||
$db = db();
|
$db = db();
|
||||||
if (isset($_POST['settings']) && is_array($_POST['settings'])) {
|
if (isset($_POST['settings']) && is_array($_POST['settings'])) {
|
||||||
foreach ($_POST['settings'] as $key => $value) {
|
$settings = $_POST['settings'];
|
||||||
|
$settings['weight_barcode_mode'] = in_array(($settings['weight_barcode_mode'] ?? 'weight'), ['weight', 'price'], true) ? $settings['weight_barcode_mode'] : 'weight';
|
||||||
|
$prefixStart = (int)($settings['weight_barcode_prefix_start'] ?? 20);
|
||||||
|
$prefixEnd = (int)($settings['weight_barcode_prefix_end'] ?? 29);
|
||||||
|
if ($prefixStart < 20 || $prefixStart > 29) $prefixStart = 20;
|
||||||
|
if ($prefixEnd < 20 || $prefixEnd > 29) $prefixEnd = 29;
|
||||||
|
if ($prefixStart > $prefixEnd) {
|
||||||
|
[$prefixStart, $prefixEnd] = [$prefixEnd, $prefixStart];
|
||||||
|
}
|
||||||
|
$settings['weight_barcode_prefix_start'] = (string)$prefixStart;
|
||||||
|
$settings['weight_barcode_prefix_end'] = (string)$prefixEnd;
|
||||||
|
|
||||||
|
foreach ($settings as $key => $value) {
|
||||||
$stmt = $db->prepare("INSERT INTO settings (`key`, `value`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `value` = ?");
|
$stmt = $db->prepare("INSERT INTO settings (`key`, `value`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `value` = ?");
|
||||||
$stmt->execute([$key, $value, $value]);
|
$stmt->execute([$key, $value, $value]);
|
||||||
}
|
}
|
||||||
@ -5132,7 +5255,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
<div class="form-grid-3">
|
<div class="form-grid-3">
|
||||||
<div class="col-md-4"><label class="form-label">Name (EN)</label><div class="input-group"><input type="text" name="name_en" id="editItemNameEn<?= $item['id'] ?>" class="form-control" value="<?= htmlspecialchars((string)($item['name_en'] ?? '')) ?>" required><button class="btn btn-outline-secondary btn-translate" type="button" data-source="editItemNameAr<?= $item['id'] ?>" data-target="editItemNameEn<?= $item['id'] ?>" data-to="en"><i class="bi bi-translate"></i> EN</button></div></div>
|
<div class="col-md-4"><label class="form-label">Name (EN)</label><div class="input-group"><input type="text" name="name_en" id="editItemNameEn<?= $item['id'] ?>" class="form-control" value="<?= htmlspecialchars((string)($item['name_en'] ?? '')) ?>" required><button class="btn btn-outline-secondary btn-translate" type="button" data-source="editItemNameAr<?= $item['id'] ?>" data-target="editItemNameEn<?= $item['id'] ?>" data-to="en"><i class="bi bi-translate"></i> EN</button></div></div>
|
||||||
<div class="col-md-4"><label class="form-label">Name (AR)</label><div class="input-group"><input type="text" name="name_ar" id="editItemNameAr<?= $item['id'] ?>" class="form-control" value="<?= htmlspecialchars((string)($item['name_ar'] ?? '')) ?>" required><button class="btn btn-outline-secondary btn-translate" type="button" data-source="editItemNameEn<?= $item['id'] ?>" data-target="editItemNameAr<?= $item['id'] ?>" data-to="ar"><i class="bi bi-translate"></i> AR</button></div></div>
|
<div class="col-md-4"><label class="form-label">Name (AR)</label><div class="input-group"><input type="text" name="name_ar" id="editItemNameAr<?= $item['id'] ?>" class="form-control" value="<?= htmlspecialchars((string)($item['name_ar'] ?? '')) ?>" required><button class="btn btn-outline-secondary btn-translate" type="button" data-source="editItemNameEn<?= $item['id'] ?>" data-target="editItemNameAr<?= $item['id'] ?>" data-to="ar"><i class="bi bi-translate"></i> AR</button></div></div>
|
||||||
<div class="col-md-4"><label class="form-label">SKU</label><input type="text" name="sku" class="form-control" value="<?= htmlspecialchars((string)($item['sku'] ?? '')) ?>"></div>
|
<div class="col-md-4"><label class="form-label">SKU</label><input type="text" name="sku" class="form-control" value="<?= htmlspecialchars((string)($item['sku'] ?? '')) ?>"><div class="form-text">13-digit scale barcodes with the reserved prefixes are not allowed here. Save the 5-digit scale item code instead.</div></div>
|
||||||
<div class="col-md-4"><label class="form-label" data-en="Category" data-ar="الفئة">Category</label><select name="category_id" class="form-select"><option value="">---</option><?php foreach ($data['categories'] ?? [] as $c): ?><option value="<?= $c['id'] ?>" <?= $c['id'] == $item['category_id'] ? 'selected' : '' ?>><?= htmlspecialchars($c['name_en']) ?></option><?php endforeach; ?></select></div>
|
<div class="col-md-4"><label class="form-label" data-en="Category" data-ar="الفئة">Category</label><select name="category_id" class="form-select"><option value="">---</option><?php foreach ($data['categories'] ?? [] as $c): ?><option value="<?= $c['id'] ?>" <?= $c['id'] == $item['category_id'] ? 'selected' : '' ?>><?= htmlspecialchars($c['name_en']) ?></option><?php endforeach; ?></select></div>
|
||||||
<div class="col-md-4"><label class="form-label">Unit</label><select name="unit_id" class="form-select"><option value="">---</option><?php foreach ($data['units'] ?? [] as $u): ?><option value="<?= $u['id'] ?>" <?= $u['id'] == $item['unit_id'] ? 'selected' : '' ?>><?= htmlspecialchars($u['short_name_en']) ?></option><?php endforeach; ?></select></div>
|
<div class="col-md-4"><label class="form-label">Unit</label><select name="unit_id" class="form-select"><option value="">---</option><?php foreach ($data['units'] ?? [] as $u): ?><option value="<?= $u['id'] ?>" <?= $u['id'] == $item['unit_id'] ? 'selected' : '' ?>><?= htmlspecialchars($u['short_name_en']) ?></option><?php endforeach; ?></select></div>
|
||||||
<div class="col-md-4"><label class="form-label" data-en="Supplier" data-ar="المورد">Supplier</label><select name="supplier_id" class="form-select"><option value="">---</option><?php foreach ($data['suppliers'] ?? [] as $s): ?><option value="<?= $s['id'] ?>" <?= $s['id'] == $item['supplier_id'] ? 'selected' : '' ?>><?= htmlspecialchars($s['name']) ?></option><?php endforeach; ?></select></div>
|
<div class="col-md-4"><label class="form-label" data-en="Supplier" data-ar="المورد">Supplier</label><select name="supplier_id" class="form-select"><option value="">---</option><?php foreach ($data['suppliers'] ?? [] as $s): ?><option value="<?= $s['id'] ?>" <?= $s['id'] == $item['supplier_id'] ? 'selected' : '' ?>><?= htmlspecialchars($s['name']) ?></option><?php endforeach; ?></select></div>
|
||||||
@ -5609,20 +5732,24 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
if (!this.items) this.items = [];
|
if (!this.items) this.items = [];
|
||||||
const allowZeroStock = (typeof companySettings !== 'undefined' && String(companySettings.allow_zero_stock_sell) === '1');
|
const allowZeroStock = (typeof companySettings !== 'undefined' && String(companySettings.allow_zero_stock_sell) === '1');
|
||||||
const currentStock = parseFloat(product.stock_quantity) || 0;
|
const currentStock = parseFloat(product.stock_quantity) || 0;
|
||||||
|
const addQty = Math.max(parseFloat(product.qty) || 1, 0.001);
|
||||||
|
const unitPrice = (product.price !== undefined && product.price !== null) ? (parseFloat(product.price) || 0) : (parseFloat(product.sale_price) || 0);
|
||||||
|
const normalizedProduct = {...product, price: unitPrice};
|
||||||
|
|
||||||
const existing = this.items.find(item => item.id === product.id);
|
const existing = this.items.find(item => item.id === product.id);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
if (!allowZeroStock && (existing.qty + 1) > currentStock) {
|
if (!allowZeroStock && (existing.qty + addQty) > currentStock) {
|
||||||
Swal.fire('Error', 'Insufficient stock!', 'error');
|
Swal.fire('Error', 'Insufficient stock!', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
existing.qty++;
|
existing.qty = Number((existing.qty + addQty).toFixed(3));
|
||||||
|
existing.price = unitPrice;
|
||||||
} else {
|
} else {
|
||||||
if (!allowZeroStock && currentStock <= 0) {
|
if (!allowZeroStock && currentStock < addQty) {
|
||||||
Swal.fire('Error', 'Insufficient stock!', 'error');
|
Swal.fire('Error', 'Insufficient stock!', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.items.push({...product, qty: 1});
|
this.items.push({...normalizedProduct, qty: Number(addQty.toFixed(3))});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
@ -6375,6 +6502,15 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
fetch('index.php?action=pos_get_item_by_sku&sku=' + encodeURIComponent(barcode))
|
fetch('index.php?action=pos_get_item_by_sku&sku=' + encodeURIComponent(barcode))
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(product => {
|
.then(product => {
|
||||||
|
if (product && product.error) {
|
||||||
|
Swal.fire({
|
||||||
|
toast: true, position: 'top-end', icon: 'error',
|
||||||
|
title: product.error, showConfirmButton: false, timer: 1800
|
||||||
|
});
|
||||||
|
e.target.select();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (product) {
|
if (product) {
|
||||||
cart.add(product);
|
cart.add(product);
|
||||||
e.target.value = '';
|
e.target.value = '';
|
||||||
@ -8785,6 +8921,24 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|||||||
<option value="1" <?= ($data['settings']['allow_zero_stock_sell'] ?? '1') === '1' ? 'selected' : '' ?> data-en="Allow selling out of stock" data-ar="السماح بالبيع عند نفاذ المخزون">Allow selling out of stock</option>
|
<option value="1" <?= ($data['settings']['allow_zero_stock_sell'] ?? '1') === '1' ? 'selected' : '' ?> data-en="Allow selling out of stock" data-ar="السماح بالبيع عند نفاذ المخزون">Allow selling out of stock</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label text-muted small fw-semibold" data-en="Scale Barcode Mode" data-ar="وضع باركود الميزان">Scale Barcode Mode</label>
|
||||||
|
<select name="settings[weight_barcode_mode]" class="form-select">
|
||||||
|
<option value="weight" <?= ($data['settings']['weight_barcode_mode'] ?? 'weight') === 'weight' ? 'selected' : '' ?> data-en="Use embedded weight" data-ar="استخدام الوزن">Use embedded weight</option>
|
||||||
|
<option value="price" <?= ($data['settings']['weight_barcode_mode'] ?? '') === 'price' ? 'selected' : '' ?> data-en="Use embedded price" data-ar="استخدام السعر">Use embedded price</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label text-muted small fw-semibold" data-en="Scale Prefix From" data-ar="بادئة الميزان من">Scale Prefix From</label>
|
||||||
|
<input type="number" min="20" max="29" name="settings[weight_barcode_prefix_start]" class="form-control" value="<?= htmlspecialchars($data['settings']['weight_barcode_prefix_start'] ?? '20') ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label text-muted small fw-semibold" data-en="Scale Prefix To" data-ar="بادئة الميزان إلى">Scale Prefix To</label>
|
||||||
|
<input type="number" min="20" max="29" name="settings[weight_barcode_prefix_end]" class="form-control" value="<?= htmlspecialchars($data['settings']['weight_barcode_prefix_end'] ?? '29') ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="form-text" data-en="13-digit scale barcode format: 2-digit prefix + 5-digit item code + 5-digit value + 1 check digit. Full 13-digit scale barcodes are reserved and cannot be saved on items or imported." data-ar="صيغة باركود الميزان 13 رقمًا: بادئة من رقمين + كود صنف من 5 أرقام + قيمة من 5 أرقام + رقم تحقق. الباركود الكامل 13 رقمًا محجوز ولا يمكن حفظه أو استيراده كصنف.">13-digit scale barcode format: 2-digit prefix + 5-digit item code + 5-digit value + 1 check digit. Full 13-digit scale barcodes are reserved and cannot be saved on items or imported.</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -9975,7 +10129,7 @@ function loadSessionReport(id) {
|
|||||||
<div class="form-grid-3">
|
<div class="form-grid-3">
|
||||||
<div class="col-md-4"><label class="form-label" data-en="Name (EN)" data-ar="الاسم (إنجليزي)">Name (EN)</label><div class="input-group"><input type="text" name="name_en" id="addItemNameEn" class="form-control" required><button class="btn btn-outline-secondary btn-translate" type="button" data-source="addItemNameAr" data-target="addItemNameEn" data-to="en"><i class="bi bi-translate"></i> EN</button></div></div>
|
<div class="col-md-4"><label class="form-label" data-en="Name (EN)" data-ar="الاسم (إنجليزي)">Name (EN)</label><div class="input-group"><input type="text" name="name_en" id="addItemNameEn" class="form-control" required><button class="btn btn-outline-secondary btn-translate" type="button" data-source="addItemNameAr" data-target="addItemNameEn" data-to="en"><i class="bi bi-translate"></i> EN</button></div></div>
|
||||||
<div class="col-md-4"><label class="form-label" data-en="Name (AR)" data-ar="الاسم (عربي)">Name (AR)</label><div class="input-group"><input type="text" name="name_ar" id="addItemNameAr" class="form-control" required><button class="btn btn-outline-secondary btn-translate" type="button" data-source="addItemNameEn" data-target="addItemNameAr" data-to="ar"><i class="bi bi-translate"></i> AR</button></div></div>
|
<div class="col-md-4"><label class="form-label" data-en="Name (AR)" data-ar="الاسم (عربي)">Name (AR)</label><div class="input-group"><input type="text" name="name_ar" id="addItemNameAr" class="form-control" required><button class="btn btn-outline-secondary btn-translate" type="button" data-source="addItemNameEn" data-target="addItemNameAr" data-to="ar"><i class="bi bi-translate"></i> AR</button></div></div>
|
||||||
<div class="col-md-4"><label class="form-label" data-en="SKU / Barcode" data-ar="الباركود">SKU / Barcode</label><div class="input-group"><input type="text" name="sku" id="skuInput" class="form-control"><button class="btn btn-outline-secondary" type="button" id="suggestSkuBtn" data-en="Suggest" data-ar="اقتراح">Suggest</button></div></div>
|
<div class="col-md-4"><label class="form-label" data-en="SKU / Barcode" data-ar="الباركود">SKU / Barcode</label><div class="input-group"><input type="text" name="sku" id="skuInput" class="form-control"><button class="btn btn-outline-secondary" type="button" id="suggestSkuBtn" data-en="Suggest" data-ar="اقتراح">Suggest</button></div><div class="form-text" data-en="Reserved 13-digit scale barcodes cannot be saved here. Use the 5-digit scale item code for weighing products." data-ar="لا يمكن حفظ باركود الميزان الكامل المكوّن من 13 رقمًا هنا. استخدم كود الصنف المكوّن من 5 أرقام لأصناف الميزان.">Reserved 13-digit scale barcodes cannot be saved here. Use the 5-digit scale item code for weighing products.</div></div>
|
||||||
<div class="col-md-4"><label class="form-label" data-en="Category" data-ar="الفئة">Category</label><select name="category_id" class="form-select"><option value="">---</option><?php foreach ($data['categories'] ?? [] as $c): ?><option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name_en']) ?> / <?= htmlspecialchars($c['name_ar']) ?></option><?php endforeach; ?></select></div>
|
<div class="col-md-4"><label class="form-label" data-en="Category" data-ar="الفئة">Category</label><select name="category_id" class="form-select"><option value="">---</option><?php foreach ($data['categories'] ?? [] as $c): ?><option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name_en']) ?> / <?= htmlspecialchars($c['name_ar']) ?></option><?php endforeach; ?></select></div>
|
||||||
<div class="col-md-4"><label class="form-label" data-en="Unit" data-ar="الوحدة">Unit</label><select name="unit_id" class="form-select"><option value="">---</option><?php foreach ($data['units'] ?? [] as $u): ?><option value="<?= $u['id'] ?>"><?= htmlspecialchars($u['short_name_en']) ?> / <?= htmlspecialchars($u['short_name_ar']) ?></option><?php endforeach; ?></select></div>
|
<div class="col-md-4"><label class="form-label" data-en="Unit" data-ar="الوحدة">Unit</label><select name="unit_id" class="form-select"><option value="">---</option><?php foreach ($data['units'] ?? [] as $u): ?><option value="<?= $u['id'] ?>"><?= htmlspecialchars($u['short_name_en']) ?> / <?= htmlspecialchars($u['short_name_ar']) ?></option><?php endforeach; ?></select></div>
|
||||||
<div class="col-md-4"><label class="form-label" data-en="Supplier" data-ar="المورد">Supplier</label><select name="supplier_id" class="form-select"><option value="">---</option><?php foreach ($data['suppliers'] ?? [] as $s): ?><option value="<?= $s['id'] ?>"><?= htmlspecialchars($s['name']) ?></option><?php endforeach; ?></select></div>
|
<div class="col-md-4"><label class="form-label" data-en="Supplier" data-ar="المورد">Supplier</label><select name="supplier_id" class="form-select"><option value="">---</option><?php foreach ($data['suppliers'] ?? [] as $s): ?><option value="<?= $s['id'] ?>"><?= htmlspecialchars($s['name']) ?></option><?php endforeach; ?></select></div>
|
||||||
@ -10010,8 +10164,8 @@ function loadSessionReport(id) {
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="alert alert-info py-2">
|
<div class="alert alert-info py-2">
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<small data-en="Please upload a CSV file with the following columns: SKU, English Name, Arabic Name, Sale Price, Cost Price." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الباركود، الاسم الإنجليزي، الاسم العربي، سعر البيع، سعر التكلفة.">
|
<small data-en="Please upload a CSV file with the following columns: SKU, English Name, Arabic Name, Sale Price, Cost Price. Reserved 13-digit scale barcodes will be skipped; save weighing products with their 5-digit item code instead." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الباركود، الاسم الإنجليزي، الاسم العربي، سعر البيع، سعر التكلفة. سيتم تجاهل باركود الميزان الكامل المكوّن من 13 رقمًا؛ احفظ أصناف الميزان باستخدام كود الصنف المكوّن من 5 أرقام.">
|
||||||
Please upload a CSV file with the following columns: SKU, English Name, Arabic Name, Sale Price, Cost Price.
|
Please upload a CSV file with the following columns: SKU, English Name, Arabic Name, Sale Price, Cost Price. Reserved 13-digit scale barcodes will be skipped; save weighing products with their 5-digit item code instead.
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<a href="index.php?action=download_items_template" class="btn btn-sm btn-primary">
|
<a href="index.php?action=download_items_template" class="btn btn-sm btn-primary">
|
||||||
|
|||||||
@ -141,3 +141,6 @@
|
|||||||
2026-03-20 17:56:51 - POST: {"id":"13","name_en":"Gold Iron Sponge 3*1","name_ar":"\u0644\u064a\u0641 \u062d\u062f\u064a\u062f \u0630\u0647\u0628\u064a 3*1","sku":"000001404142","category_id":"","unit_id":"","supplier_id":"","sale_price":"0.2","purchase_price":"0.125","stock_quantity":"-1","min_stock_level":"0","vat_rate":"0.00","promotion_start":"","promotion_end":"","promotion_percent":"0","edit_item":""}
|
2026-03-20 17:56:51 - POST: {"id":"13","name_en":"Gold Iron Sponge 3*1","name_ar":"\u0644\u064a\u0641 \u062d\u062f\u064a\u062f \u0630\u0647\u0628\u064a 3*1","sku":"000001404142","category_id":"","unit_id":"","supplier_id":"","sale_price":"0.2","purchase_price":"0.125","stock_quantity":"-1","min_stock_level":"0","vat_rate":"0.00","promotion_start":"","promotion_end":"","promotion_percent":"0","edit_item":""}
|
||||||
2026-03-20 18:02:45 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":0.7}]","total_amount":"0.7","tax_amount":"0.023809523809523808","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":56,\"qty\":1,\"price\":0.2,\"vat_rate\":0,\"vat_amount\":0},{\"id\":62,\"qty\":2,\"price\":0.25,\"vat_rate\":5,\"vat_amount\":0.023809523809523808}]"}
|
2026-03-20 18:02:45 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":0.7}]","total_amount":"0.7","tax_amount":"0.023809523809523808","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":56,\"qty\":1,\"price\":0.2,\"vat_rate\":0,\"vat_amount\":0},{\"id\":62,\"qty\":2,\"price\":0.25,\"vat_rate\":5,\"vat_amount\":0.023809523809523808}]"}
|
||||||
2026-03-20 18:25:38 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":3.15}]","total_amount":"3.15","tax_amount":"0","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":36,\"qty\":1,\"price\":1.45,\"vat_rate\":0,\"vat_amount\":0},{\"id\":18,\"qty\":1,\"price\":0.6,\"vat_rate\":0,\"vat_amount\":0},{\"id\":30,\"qty\":1,\"price\":1.1,\"vat_rate\":0,\"vat_amount\":0}]"}
|
2026-03-20 18:25:38 - POST: {"action":"save_pos_transaction","customer_id":"","payments":"[{\"method\":\"cash\",\"amount\":3.15}]","total_amount":"3.15","tax_amount":"0","discount_code_id":"","discount_amount":"0","loyalty_redeemed":"0","items":"[{\"id\":36,\"qty\":1,\"price\":1.45,\"vat_rate\":0,\"vat_amount\":0},{\"id\":18,\"qty\":1,\"price\":0.6,\"vat_rate\":0,\"vat_amount\":0},{\"id\":30,\"qty\":1,\"price\":1.1,\"vat_rate\":0,\"vat_amount\":0}]"}
|
||||||
|
2026-04-09 04:06:44 - POST: {"start_trial":""}
|
||||||
|
2026-04-09 04:06:58 - POST: {"username":"admin","password":"admin","login":""}
|
||||||
|
2026-04-09 04:08:44 - POST: {"username":"admin","password":"admin","login":"1"}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user