update index
This commit is contained in:
parent
4f16b7540a
commit
82a5fde6bc
BIN
assets/pasted-20260506-134907-6b1d58c7.png
Normal file
BIN
assets/pasted-20260506-134907-6b1d58c7.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
19
index.php
19
index.php
@ -5887,6 +5887,21 @@ runtime_debug_mark('page:rendering', ['page' => (string)$page]);
|
||||
.units-table tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
.items-list-heading {
|
||||
font-size: calc(1.25rem + 1px);
|
||||
font-weight: 800;
|
||||
color: #1d4ed8;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
.items-list-table thead th {
|
||||
font-size: 0.82rem;
|
||||
font-weight: 800;
|
||||
color: #1d4ed8;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
background: rgba(29, 78, 216, 0.08);
|
||||
border-bottom-color: rgba(29, 78, 216, 0.18);
|
||||
}
|
||||
.units-name-stack {
|
||||
display: grid;
|
||||
gap: 0.2rem;
|
||||
@ -7181,7 +7196,7 @@ runtime_debug_mark('page:rendering', ['page' => (string)$page]);
|
||||
<?php elseif ($page === 'items'): ?>
|
||||
<div class="card p-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h5 class="m-0" data-en="Stock Items" data-ar="أصناف المخزون">Stock Items (<?= count($data['items'] ?? []) ?>)</h5>
|
||||
<h5 class="m-0 items-list-heading" data-en="Stock Items" data-ar="أصناف المخزون">Stock Items (<?= count($data['items'] ?? []) ?>)</h5>
|
||||
<div class="d-flex align-items-center">
|
||||
<button class="btn btn-dark me-2" id="bulkBarcodeBtn" style="display:none;" onclick="openAveryModal()">
|
||||
<i class="bi bi-printer"></i> <span data-en="Avery Labels" data-ar="ملصقات إيفري">Avery Labels</span>
|
||||
@ -7266,7 +7281,7 @@ runtime_debug_mark('page:rendering', ['page' => (string)$page]);
|
||||
</form>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle">
|
||||
<table class="table table-hover align-middle items-list-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 40px;"><input type="checkbox" id="selectAllItems" class="form-check-input"></th>
|
||||
|
||||
@ -98,13 +98,13 @@
|
||||
|
||||
container.style.width = '100%';
|
||||
container.style.maxWidth = '100%';
|
||||
container.style.lineHeight = '1.05';
|
||||
container.style.lineHeight = '1';
|
||||
container.style.marginBottom = '0';
|
||||
|
||||
if (arabicLine) {
|
||||
arabicLine.style.display = 'block';
|
||||
arabicLine.style.fontWeight = '700';
|
||||
arabicLine.style.fontSize = compact ? '0.98rem' : '1.10rem';
|
||||
arabicLine.style.fontSize = compact ? '1.04rem' : '1.16rem';
|
||||
arabicLine.style.direction = 'rtl';
|
||||
arabicLine.style.whiteSpace = 'nowrap';
|
||||
arabicLine.style.overflow = 'hidden';
|
||||
@ -114,7 +114,7 @@
|
||||
if (englishLine) {
|
||||
englishLine.style.display = 'block';
|
||||
englishLine.style.fontWeight = '600';
|
||||
englishLine.style.fontSize = compact ? '0.84rem' : '0.95rem';
|
||||
englishLine.style.fontSize = compact ? '0.90rem' : '0.99rem';
|
||||
englishLine.style.whiteSpace = 'nowrap';
|
||||
englishLine.style.overflow = 'hidden';
|
||||
englishLine.style.textOverflow = 'ellipsis';
|
||||
@ -127,21 +127,21 @@
|
||||
}
|
||||
|
||||
container.style.width = '100%';
|
||||
container.style.maxWidth = '240px';
|
||||
container.style.maxWidth = '260px';
|
||||
container.style.direction = 'ltr';
|
||||
container.style.textAlign = 'center';
|
||||
container.style.lineHeight = '1.05';
|
||||
container.style.lineHeight = '1';
|
||||
container.style.fontWeight = '600';
|
||||
container.style.fontSize = compact ? '0.80rem' : '0.92rem';
|
||||
container.style.fontSize = compact ? '0.88rem' : '0.98rem';
|
||||
container.style.marginTop = '0';
|
||||
|
||||
const row = container.querySelector('.label-date-row');
|
||||
if (row) {
|
||||
row.style.gap = compact ? '10px' : '14px';
|
||||
row.style.gap = compact ? '8px' : '12px';
|
||||
}
|
||||
|
||||
container.querySelectorAll('.label-date-item').forEach((item) => {
|
||||
item.style.gap = compact ? '4px' : '6px';
|
||||
item.style.gap = compact ? '3px' : '5px';
|
||||
});
|
||||
}
|
||||
|
||||
@ -186,7 +186,7 @@
|
||||
priceContainer.textContent = label.price ? 'OMR ' + label.price : '';
|
||||
priceContainer.style.display = label.price ? 'block' : 'none';
|
||||
priceContainer.style.fontWeight = '700';
|
||||
priceContainer.style.fontSize = compact ? '0.98rem' : '1.08rem';
|
||||
priceContainer.style.fontSize = compact ? '1.04rem' : '1.14rem';
|
||||
priceContainer.style.lineHeight = '1';
|
||||
priceContainer.style.marginTop = '0';
|
||||
|
||||
@ -194,10 +194,10 @@
|
||||
previewContainer.style.flexDirection = 'column';
|
||||
previewContainer.style.alignItems = 'center';
|
||||
previewContainer.style.justifyContent = 'center';
|
||||
previewContainer.style.gap = compact ? '4px' : '6px';
|
||||
previewContainer.style.gap = compact ? '3px' : '4px';
|
||||
previewContainer.style.width = Math.min(Math.max(width * 3.8, 185), 310) + 'px';
|
||||
previewContainer.style.maxWidth = '100%';
|
||||
previewContainer.style.padding = height <= 25 ? '10px 12px' : '12px 14px';
|
||||
previewContainer.style.padding = height <= 25 ? '9px 11px' : '11px 13px';
|
||||
|
||||
svg.innerHTML = '';
|
||||
JsBarcode(svg, label.sku, getSingleBarcodeOptions(label.sku, width, height));
|
||||
@ -299,14 +299,14 @@
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
padding: 1.1mm 1.8mm 1.2mm;
|
||||
gap: 0.45mm;
|
||||
padding: 0.9mm 1.55mm 1mm;
|
||||
gap: 0.25mm;
|
||||
}
|
||||
.label-container:last-child { page-break-after: avoid; }
|
||||
.label-name {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
line-height: 1.02;
|
||||
line-height: 1;
|
||||
}
|
||||
.label-name-ar,
|
||||
.label-name-en {
|
||||
@ -317,33 +317,33 @@
|
||||
}
|
||||
.label-name-ar {
|
||||
font-weight: 700;
|
||||
font-size: 12px;
|
||||
font-size: 13.4px;
|
||||
direction: rtl;
|
||||
}
|
||||
.label-name-en {
|
||||
font-size: 10px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.label-price {
|
||||
font-size: 12px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.label-compact {
|
||||
padding: 0.85mm 1.3mm 0.95mm;
|
||||
gap: 0.35mm;
|
||||
padding: 0.7mm 1.15mm 0.75mm;
|
||||
gap: 0.2mm;
|
||||
}
|
||||
.label-compact .label-name-ar { font-size: 10.5px; }
|
||||
.label-compact .label-name-en { font-size: 8.75px; }
|
||||
.label-compact .label-price { font-size: 10.5px; }
|
||||
.label-compact .label-name-ar { font-size: 11.6px; }
|
||||
.label-compact .label-name-en { font-size: 9.6px; }
|
||||
.label-compact .label-price { font-size: 11.5px; }
|
||||
.barcode-wrap {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 1mm;
|
||||
margin: 0.15mm 0;
|
||||
padding: 0 0.8mm;
|
||||
margin: 0.1mm 0;
|
||||
overflow: visible;
|
||||
}
|
||||
.barcode-wrap svg {
|
||||
@ -483,7 +483,7 @@
|
||||
priceContainer.textContent = label.price ? 'OMR ' + label.price : '';
|
||||
priceContainer.style.display = label.price ? 'block' : 'none';
|
||||
priceContainer.style.fontWeight = '700';
|
||||
priceContainer.style.fontSize = compact ? '0.90rem' : '1.02rem';
|
||||
priceContainer.style.fontSize = compact ? '0.98rem' : '1.08rem';
|
||||
priceContainer.style.lineHeight = '1';
|
||||
priceContainer.style.marginTop = '0';
|
||||
}
|
||||
@ -492,10 +492,10 @@
|
||||
previewContainer.style.flexDirection = 'column';
|
||||
previewContainer.style.alignItems = 'center';
|
||||
previewContainer.style.justifyContent = 'center';
|
||||
previewContainer.style.gap = compact ? '4px' : '5px';
|
||||
previewContainer.style.gap = compact ? '3px' : '4px';
|
||||
previewContainer.style.width = Math.min(Math.max(width * 4.0, 190), 320) + 'px';
|
||||
previewContainer.style.maxWidth = '100%';
|
||||
previewContainer.style.padding = height <= 30 ? '10px 11px' : '11px 13px';
|
||||
previewContainer.style.padding = height <= 30 ? '9px 10px' : '10px 12px';
|
||||
|
||||
svg.innerHTML = '';
|
||||
JsBarcode(svg, label.sku, getDatedBarcodeOptions(label.sku, width, height));
|
||||
@ -625,13 +625,13 @@
|
||||
}
|
||||
.label-container:last-child { page-break-after: avoid; }
|
||||
.dated-label {
|
||||
padding: 0.95mm 1.45mm 1mm;
|
||||
gap: 0.3mm;
|
||||
padding: 0.78mm 1.25mm 0.8mm;
|
||||
gap: 0.2mm;
|
||||
}
|
||||
.label-name {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
line-height: 1.02;
|
||||
line-height: 1;
|
||||
}
|
||||
.label-name-ar,
|
||||
.label-name-en {
|
||||
@ -642,11 +642,11 @@
|
||||
}
|
||||
.label-name-ar {
|
||||
font-weight: 700;
|
||||
font-size: 11.5px;
|
||||
font-size: 13px;
|
||||
direction: rtl;
|
||||
}
|
||||
.label-name-en {
|
||||
font-size: 9.5px;
|
||||
font-size: 10.6px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.label-meta {
|
||||
@ -655,8 +655,8 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.25mm;
|
||||
margin-top: 0.1mm;
|
||||
gap: 0.15mm;
|
||||
margin-top: 0;
|
||||
}
|
||||
.label-dates {
|
||||
--label-date-row-gap: 1.2mm;
|
||||
@ -667,7 +667,7 @@
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
direction: ltr;
|
||||
font-size: 9px;
|
||||
font-size: 10.1px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
}
|
||||
@ -687,31 +687,31 @@
|
||||
font-weight: 700;
|
||||
}
|
||||
.label-price {
|
||||
font-size: 10px;
|
||||
font-size: 11.2px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.label-compact {
|
||||
padding: 0.75mm 1.05mm 0.8mm;
|
||||
gap: 0.25mm;
|
||||
padding: 0.58mm 0.95mm 0.6mm;
|
||||
gap: 0.15mm;
|
||||
}
|
||||
.label-compact .label-name-ar { font-size: 10px; }
|
||||
.label-compact .label-name-en { font-size: 8.3px; }
|
||||
.label-compact .label-meta { gap: 0.2mm; }
|
||||
.label-compact .label-name-ar { font-size: 11.1px; }
|
||||
.label-compact .label-name-en { font-size: 9.1px; }
|
||||
.label-compact .label-meta { gap: 0.12mm; }
|
||||
.label-compact .label-dates {
|
||||
--label-date-row-gap: 0.85mm;
|
||||
--label-date-item-gap: 0.35mm;
|
||||
font-size: 7.8px;
|
||||
font-size: 8.7px;
|
||||
}
|
||||
.label-compact .label-price { font-size: 8.8px; }
|
||||
.label-compact .label-price { font-size: 9.7px; }
|
||||
.barcode-wrap {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 0.7mm;
|
||||
margin: 0.15mm 0;
|
||||
padding: 0 0.55mm;
|
||||
margin: 0.08mm 0;
|
||||
overflow: visible;
|
||||
}
|
||||
.barcode-wrap svg {
|
||||
|
||||
843
tmp_barcode_pos_script_check.js
Normal file
843
tmp_barcode_pos_script_check.js
Normal file
@ -0,0 +1,843 @@
|
||||
function escapeBarcodeLabelHtml(value) {
|
||||
return String(value || '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function getSingleBarcodeLabelData() {
|
||||
return window.currentSingleBarcodeLabel || null;
|
||||
}
|
||||
|
||||
function getSingleBarcodePrintDimensions() {
|
||||
return {
|
||||
width: Math.max(parseInt(document.getElementById('barcodeWidth').value, 10) || 50, 10),
|
||||
height: Math.max(parseInt(document.getElementById('barcodeHeight').value, 10) || 30, 10)
|
||||
};
|
||||
}
|
||||
|
||||
function getSingleBarcodeScale(labelWidthMm, labelHeightMm) {
|
||||
if (labelWidthMm <= 32 || labelHeightMm <= 20) {
|
||||
return 0.96;
|
||||
}
|
||||
if (labelWidthMm <= 40 || labelHeightMm <= 25) {
|
||||
return 0.92;
|
||||
}
|
||||
if (labelWidthMm <= 50 || labelHeightMm <= 30) {
|
||||
return 0.88;
|
||||
}
|
||||
return 0.84;
|
||||
}
|
||||
|
||||
function getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm) {
|
||||
const skuText = String(sku || '');
|
||||
const skuLength = skuText.length;
|
||||
const compact = labelWidthMm <= 40 || labelHeightMm <= 25;
|
||||
const extraCompact = labelWidthMm <= 32 || labelHeightMm <= 20;
|
||||
const showValue = !extraCompact && labelHeightMm >= 24 && skuLength <= 18;
|
||||
|
||||
let moduleWidth = 1.8;
|
||||
if (skuLength >= 18 || labelWidthMm <= 35) {
|
||||
moduleWidth = 1.1;
|
||||
} else if (skuLength >= 14 || labelWidthMm <= 40) {
|
||||
moduleWidth = 1.3;
|
||||
} else if (labelWidthMm <= 50) {
|
||||
moduleWidth = 1.6;
|
||||
}
|
||||
|
||||
let barcodeHeight = 56;
|
||||
if (labelHeightMm <= 20) {
|
||||
barcodeHeight = 30;
|
||||
} else if (labelHeightMm <= 25) {
|
||||
barcodeHeight = 38;
|
||||
} else if (labelHeightMm <= 30) {
|
||||
barcodeHeight = 46;
|
||||
} else if (labelHeightMm <= 35) {
|
||||
barcodeHeight = 56;
|
||||
} else {
|
||||
barcodeHeight = 64;
|
||||
}
|
||||
|
||||
const quietZone = extraCompact ? 4 : compact ? 6 : 10;
|
||||
|
||||
return {
|
||||
format: "CODE128",
|
||||
lineColor: "#000",
|
||||
width: moduleWidth,
|
||||
height: barcodeHeight,
|
||||
displayValue: showValue,
|
||||
fontSize: compact ? 10 : 12,
|
||||
textMargin: compact ? 2 : 4,
|
||||
margin: quietZone,
|
||||
marginTop: 0,
|
||||
marginBottom: showValue ? 2 : 0,
|
||||
fontOptions: "bold"
|
||||
};
|
||||
}
|
||||
|
||||
function buildSingleBarcodeNameHtml(nameAr, nameEn) {
|
||||
const lines = [];
|
||||
if (nameAr) {
|
||||
lines.push('<div class="label-name-ar">' + escapeBarcodeLabelHtml(nameAr) + '</div>');
|
||||
}
|
||||
if (nameEn) {
|
||||
lines.push('<div class="label-name-en">' + escapeBarcodeLabelHtml(nameEn) + '</div>');
|
||||
}
|
||||
return lines.join('');
|
||||
}
|
||||
|
||||
function applyBarcodePreviewNameStyles(container, compact) {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const arabicLine = container.querySelector('.label-name-ar');
|
||||
const englishLine = container.querySelector('.label-name-en');
|
||||
|
||||
container.style.width = '100%';
|
||||
container.style.maxWidth = '100%';
|
||||
container.style.lineHeight = '1';
|
||||
container.style.marginBottom = '0';
|
||||
|
||||
if (arabicLine) {
|
||||
arabicLine.style.display = 'block';
|
||||
arabicLine.style.fontWeight = '700';
|
||||
arabicLine.style.fontSize = compact ? '1.04rem' : '1.16rem';
|
||||
arabicLine.style.direction = 'rtl';
|
||||
arabicLine.style.whiteSpace = 'nowrap';
|
||||
arabicLine.style.overflow = 'hidden';
|
||||
arabicLine.style.textOverflow = 'ellipsis';
|
||||
}
|
||||
|
||||
if (englishLine) {
|
||||
englishLine.style.display = 'block';
|
||||
englishLine.style.fontWeight = '600';
|
||||
englishLine.style.fontSize = compact ? '0.90rem' : '0.99rem';
|
||||
englishLine.style.whiteSpace = 'nowrap';
|
||||
englishLine.style.overflow = 'hidden';
|
||||
englishLine.style.textOverflow = 'ellipsis';
|
||||
}
|
||||
}
|
||||
|
||||
function applyBarcodePreviewDateStyles(container, compact) {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
container.style.width = '100%';
|
||||
container.style.maxWidth = '260px';
|
||||
container.style.direction = 'ltr';
|
||||
container.style.textAlign = 'center';
|
||||
container.style.lineHeight = '1';
|
||||
container.style.fontWeight = '600';
|
||||
container.style.fontSize = compact ? '0.88rem' : '0.98rem';
|
||||
container.style.marginTop = '0';
|
||||
|
||||
const row = container.querySelector('.label-date-row');
|
||||
if (row) {
|
||||
row.style.gap = compact ? '8px' : '12px';
|
||||
}
|
||||
|
||||
container.querySelectorAll('.label-date-item').forEach((item) => {
|
||||
item.style.gap = compact ? '3px' : '5px';
|
||||
});
|
||||
}
|
||||
|
||||
function buildSingleBarcodeSvgMarkup(sku, labelWidthMm, labelHeightMm) {
|
||||
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
const scale = getSingleBarcodeScale(labelWidthMm, labelHeightMm);
|
||||
JsBarcode(svg, sku, getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm));
|
||||
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
||||
svg.setAttribute('shape-rendering', 'crispEdges');
|
||||
svg.style.width = Math.round(scale * 100) + '%';
|
||||
svg.style.maxWidth = '100%';
|
||||
svg.style.height = 'auto';
|
||||
svg.style.display = 'block';
|
||||
svg.style.margin = '0 auto';
|
||||
svg.style.shapeRendering = 'crispEdges';
|
||||
return svg.outerHTML;
|
||||
}
|
||||
|
||||
function renderSingleBarcodePreview() {
|
||||
const label = getSingleBarcodeLabelData();
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dimensions = getSingleBarcodePrintDimensions();
|
||||
const width = dimensions.width;
|
||||
const height = dimensions.height;
|
||||
const scale = getSingleBarcodeScale(width, height);
|
||||
const compact = width <= 40 || height <= 25;
|
||||
const nameContainer = document.getElementById('barcodeLabelName');
|
||||
const priceContainer = document.getElementById('barcodeLabelPrice');
|
||||
const previewContainer = document.getElementById('barcodeContainer');
|
||||
const svg = document.getElementById('barcodeSvg');
|
||||
|
||||
if (!nameContainer || !priceContainer || !previewContainer || !svg) {
|
||||
return;
|
||||
}
|
||||
|
||||
nameContainer.innerHTML = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn);
|
||||
applyBarcodePreviewNameStyles(nameContainer, compact);
|
||||
|
||||
priceContainer.textContent = label.price ? 'OMR ' + label.price : '';
|
||||
priceContainer.style.display = label.price ? 'block' : 'none';
|
||||
priceContainer.style.fontWeight = '700';
|
||||
priceContainer.style.fontSize = compact ? '1.04rem' : '1.14rem';
|
||||
priceContainer.style.lineHeight = '1';
|
||||
priceContainer.style.marginTop = '0';
|
||||
|
||||
previewContainer.style.display = 'flex';
|
||||
previewContainer.style.flexDirection = 'column';
|
||||
previewContainer.style.alignItems = 'center';
|
||||
previewContainer.style.justifyContent = 'center';
|
||||
previewContainer.style.gap = compact ? '3px' : '4px';
|
||||
previewContainer.style.width = Math.min(Math.max(width * 3.8, 185), 310) + 'px';
|
||||
previewContainer.style.maxWidth = '100%';
|
||||
previewContainer.style.padding = height <= 25 ? '9px 11px' : '11px 13px';
|
||||
|
||||
svg.innerHTML = '';
|
||||
JsBarcode(svg, label.sku, getSingleBarcodeOptions(label.sku, width, height));
|
||||
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
||||
svg.setAttribute('shape-rendering', 'crispEdges');
|
||||
svg.style.width = Math.round(scale * 100) + '%';
|
||||
svg.style.maxWidth = '100%';
|
||||
svg.style.height = 'auto';
|
||||
svg.style.display = 'block';
|
||||
svg.style.margin = '0 auto';
|
||||
svg.style.shapeRendering = 'crispEdges';
|
||||
}
|
||||
|
||||
function initSingleBarcodePreviewControls() {
|
||||
['barcodeWidth', 'barcodeHeight'].forEach((id) => {
|
||||
const input = document.getElementById(id);
|
||||
if (!input || input.dataset.barcodePreviewBound === '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
input.dataset.barcodePreviewBound = '1';
|
||||
input.addEventListener('input', renderSingleBarcodePreview);
|
||||
input.addEventListener('change', renderSingleBarcodePreview);
|
||||
});
|
||||
}
|
||||
|
||||
initSingleBarcodePreviewControls();
|
||||
|
||||
window.printItemBarcode = function(sku, nameAr, nameEn, price) {
|
||||
if (!sku) {
|
||||
Swal.fire('Error', 'This item has no SKU/Barcode assigned.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
window.currentSingleBarcodeLabel = {
|
||||
sku: String(sku),
|
||||
nameAr: nameAr || '',
|
||||
nameEn: nameEn || '',
|
||||
price: price || ''
|
||||
};
|
||||
|
||||
renderSingleBarcodePreview();
|
||||
|
||||
const modal = new bootstrap.Modal(document.getElementById('barcodePrintModal'));
|
||||
modal.show();
|
||||
};
|
||||
|
||||
window.executeBarcodePrint = function() {
|
||||
const qty = Math.max(parseInt(document.getElementById('barcodeQty').value, 10) || 1, 1);
|
||||
const dimensions = getSingleBarcodePrintDimensions();
|
||||
const width = dimensions.width;
|
||||
const height = dimensions.height;
|
||||
const label = getSingleBarcodeLabelData();
|
||||
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nameHtml = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn);
|
||||
const price = label.price ? 'OMR ' + escapeBarcodeLabelHtml(label.price) : '';
|
||||
const svg = buildSingleBarcodeSvgMarkup(label.sku, width, height);
|
||||
const compactClass = width <= 40 || height <= 25 ? 'label-compact' : '';
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.style.position = 'absolute';
|
||||
iframe.style.width = '0px';
|
||||
iframe.style.height = '0px';
|
||||
iframe.style.border = 'none';
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
const doc = iframe.contentWindow.document;
|
||||
|
||||
let labelsHtml = '';
|
||||
for (let i = 0; i < qty; i++) {
|
||||
labelsHtml += `
|
||||
<div class="label-container ${compactClass}">
|
||||
${nameHtml ? `<div class="label-name">${nameHtml}</div>` : ''}
|
||||
<div class="barcode-wrap">${svg}</div>
|
||||
${price ? `<div class="label-price">${price}</div>` : ''}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
doc.open();
|
||||
doc.write(`
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
@page { size: ${width}mm ${height}mm; margin: 0; }
|
||||
body { margin: 0; padding: 0; font-family: sans-serif; }
|
||||
.label-container {
|
||||
width: ${width}mm;
|
||||
height: ${height}mm;
|
||||
page-break-after: always;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
padding: 0.9mm 1.55mm 1mm;
|
||||
gap: 0.25mm;
|
||||
}
|
||||
.label-container:last-child { page-break-after: avoid; }
|
||||
.label-name {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
line-height: 1;
|
||||
}
|
||||
.label-name-ar,
|
||||
.label-name-en {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.label-name-ar {
|
||||
font-weight: 700;
|
||||
font-size: 13.4px;
|
||||
direction: rtl;
|
||||
}
|
||||
.label-name-en {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.label-price {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.label-compact {
|
||||
padding: 0.7mm 1.15mm 0.75mm;
|
||||
gap: 0.2mm;
|
||||
}
|
||||
.label-compact .label-name-ar { font-size: 11.6px; }
|
||||
.label-compact .label-name-en { font-size: 9.6px; }
|
||||
.label-compact .label-price { font-size: 11.5px; }
|
||||
.barcode-wrap {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 0.8mm;
|
||||
margin: 0.1mm 0;
|
||||
overflow: visible;
|
||||
}
|
||||
.barcode-wrap svg {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
overflow: visible;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${labelsHtml}
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
doc.close();
|
||||
|
||||
iframe.contentWindow.focus();
|
||||
setTimeout(() => {
|
||||
iframe.contentWindow.print();
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(iframe);
|
||||
}, 2000);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
function formatBarcodeLabelDate(value) {
|
||||
const dateText = String(value || '').trim();
|
||||
const match = dateText.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
||||
if (match) {
|
||||
return `${match[3]}/${match[2]}/${match[1]}`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function buildDatedBarcodeDateRowsHtml(productionDate, expiryDate) {
|
||||
const productionText = formatBarcodeLabelDate(productionDate) || '--/--/----';
|
||||
const expiryText = formatBarcodeLabelDate(expiryDate) || '--/--/----';
|
||||
|
||||
return `
|
||||
<div class="label-date-row" style="display:flex;align-items:center;justify-content:center;gap:var(--label-date-row-gap,8px);direction:ltr;text-align:center;white-space:nowrap;">
|
||||
<span class="label-date-item" style="display:inline-flex;align-items:center;gap:var(--label-date-item-gap,4px);white-space:nowrap;"><span class="label-date-key">P:</span><span class="label-date-value">${escapeBarcodeLabelHtml(productionText)}</span></span>
|
||||
<span class="label-date-item" style="display:inline-flex;align-items:center;gap:var(--label-date-item-gap,4px);white-space:nowrap;"><span class="label-date-key">E:</span><span class="label-date-value">${escapeBarcodeLabelHtml(expiryText)}</span></span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function getDatedBarcodeLabelData() {
|
||||
return window.currentDatedBarcodeLabel || null;
|
||||
}
|
||||
|
||||
function getDatedBarcodePrintDimensions() {
|
||||
return {
|
||||
width: Math.max(parseInt(document.getElementById('datedBarcodeWidth').value, 10) || 50, 10),
|
||||
height: Math.max(parseInt(document.getElementById('datedBarcodeHeight').value, 10) || 35, 10)
|
||||
};
|
||||
}
|
||||
|
||||
function getDatedBarcodeScale(labelWidthMm, labelHeightMm) {
|
||||
if (labelWidthMm <= 32 || labelHeightMm <= 24) {
|
||||
return 0.96;
|
||||
}
|
||||
if (labelWidthMm <= 40 || labelHeightMm <= 30) {
|
||||
return 0.95;
|
||||
}
|
||||
if (labelWidthMm <= 50 || labelHeightMm <= 35) {
|
||||
return 0.94;
|
||||
}
|
||||
return 0.90;
|
||||
}
|
||||
|
||||
function getDatedBarcodeOptions(sku, labelWidthMm, labelHeightMm) {
|
||||
const baseOptions = getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm);
|
||||
const skuLength = String(sku || '').length;
|
||||
const showValue = labelHeightMm >= 46 && labelWidthMm >= 50 && skuLength <= 16;
|
||||
|
||||
return {
|
||||
...baseOptions,
|
||||
displayValue: showValue,
|
||||
fontSize: showValue ? 10 : 8,
|
||||
textMargin: showValue ? 2 : 0,
|
||||
height: Math.max(Math.round(baseOptions.height * (showValue ? 0.88 : 0.96)), 28),
|
||||
margin: Math.max(baseOptions.margin, 6),
|
||||
marginBottom: showValue ? 1 : 0
|
||||
};
|
||||
}
|
||||
|
||||
function buildDatedBarcodeSvgMarkup(sku, labelWidthMm, labelHeightMm) {
|
||||
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
const scale = getDatedBarcodeScale(labelWidthMm, labelHeightMm);
|
||||
JsBarcode(svg, sku, getDatedBarcodeOptions(sku, labelWidthMm, labelHeightMm));
|
||||
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
||||
svg.setAttribute('shape-rendering', 'crispEdges');
|
||||
svg.style.width = Math.round(scale * 100) + '%';
|
||||
svg.style.maxWidth = '100%';
|
||||
svg.style.height = 'auto';
|
||||
svg.style.display = 'block';
|
||||
svg.style.margin = '0 auto';
|
||||
svg.style.shapeRendering = 'crispEdges';
|
||||
return svg.outerHTML;
|
||||
}
|
||||
|
||||
function renderDatedBarcodePreview() {
|
||||
const label = getDatedBarcodeLabelData();
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dimensions = getDatedBarcodePrintDimensions();
|
||||
const width = dimensions.width;
|
||||
const height = dimensions.height;
|
||||
const scale = getDatedBarcodeScale(width, height);
|
||||
const compact = width <= 40 || height <= 30;
|
||||
const nameContainer = document.getElementById('datedBarcodeLabelName');
|
||||
const datesContainer = document.getElementById('datedBarcodeLabelDates');
|
||||
const priceContainer = document.getElementById('datedBarcodeLabelPrice');
|
||||
const previewContainer = document.getElementById('datedBarcodeContainer');
|
||||
const svg = document.getElementById('datedBarcodeSvg');
|
||||
const productionInput = document.getElementById('datedBarcodeProductionDate');
|
||||
const expiryInput = document.getElementById('datedBarcodeExpiryDate');
|
||||
|
||||
if (!nameContainer || !datesContainer || !previewContainer || !svg) {
|
||||
return;
|
||||
}
|
||||
|
||||
nameContainer.innerHTML = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn);
|
||||
applyBarcodePreviewNameStyles(nameContainer, compact);
|
||||
|
||||
datesContainer.innerHTML = buildDatedBarcodeDateRowsHtml(
|
||||
productionInput ? productionInput.value : '',
|
||||
expiryInput ? expiryInput.value : ''
|
||||
);
|
||||
applyBarcodePreviewDateStyles(datesContainer, compact);
|
||||
|
||||
if (priceContainer) {
|
||||
priceContainer.textContent = label.price ? 'OMR ' + label.price : '';
|
||||
priceContainer.style.display = label.price ? 'block' : 'none';
|
||||
priceContainer.style.fontWeight = '700';
|
||||
priceContainer.style.fontSize = compact ? '0.98rem' : '1.08rem';
|
||||
priceContainer.style.lineHeight = '1';
|
||||
priceContainer.style.marginTop = '0';
|
||||
}
|
||||
|
||||
previewContainer.style.display = 'flex';
|
||||
previewContainer.style.flexDirection = 'column';
|
||||
previewContainer.style.alignItems = 'center';
|
||||
previewContainer.style.justifyContent = 'center';
|
||||
previewContainer.style.gap = compact ? '3px' : '4px';
|
||||
previewContainer.style.width = Math.min(Math.max(width * 4.0, 190), 320) + 'px';
|
||||
previewContainer.style.maxWidth = '100%';
|
||||
previewContainer.style.padding = height <= 30 ? '9px 10px' : '10px 12px';
|
||||
|
||||
svg.innerHTML = '';
|
||||
JsBarcode(svg, label.sku, getDatedBarcodeOptions(label.sku, width, height));
|
||||
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
||||
svg.setAttribute('shape-rendering', 'crispEdges');
|
||||
svg.style.width = Math.round(scale * 100) + '%';
|
||||
svg.style.maxWidth = '100%';
|
||||
svg.style.height = 'auto';
|
||||
svg.style.display = 'block';
|
||||
svg.style.margin = '0 auto';
|
||||
svg.style.shapeRendering = 'crispEdges';
|
||||
}
|
||||
|
||||
function initDatedBarcodePreviewControls() {
|
||||
['datedBarcodeWidth', 'datedBarcodeHeight', 'datedBarcodeProductionDate', 'datedBarcodeExpiryDate'].forEach((id) => {
|
||||
const input = document.getElementById(id);
|
||||
if (!input || input.dataset.barcodePreviewBound === '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
input.dataset.barcodePreviewBound = '1';
|
||||
input.addEventListener('input', renderDatedBarcodePreview);
|
||||
input.addEventListener('change', renderDatedBarcodePreview);
|
||||
});
|
||||
}
|
||||
|
||||
initDatedBarcodePreviewControls();
|
||||
|
||||
window.printItemBarcodeWithDates = function(sku, nameAr, nameEn, price, defaultExpiryDate) {
|
||||
if (!sku) {
|
||||
Swal.fire('Error', 'This item has no SKU/Barcode assigned.', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
window.currentDatedBarcodeLabel = {
|
||||
sku: String(sku),
|
||||
nameAr: nameAr || '',
|
||||
nameEn: nameEn || '',
|
||||
price: price || ''
|
||||
};
|
||||
|
||||
const productionInput = document.getElementById('datedBarcodeProductionDate');
|
||||
const expiryInput = document.getElementById('datedBarcodeExpiryDate');
|
||||
if (productionInput) {
|
||||
productionInput.value = '';
|
||||
}
|
||||
if (expiryInput) {
|
||||
expiryInput.value = defaultExpiryDate || '';
|
||||
}
|
||||
|
||||
renderDatedBarcodePreview();
|
||||
|
||||
const modal = new bootstrap.Modal(document.getElementById('datedBarcodePrintModal'));
|
||||
modal.show();
|
||||
};
|
||||
|
||||
window.executeDatedBarcodePrint = function() {
|
||||
const qty = Math.max(parseInt(document.getElementById('datedBarcodeQty').value, 10) || 1, 1);
|
||||
const dimensions = getDatedBarcodePrintDimensions();
|
||||
const width = dimensions.width;
|
||||
const height = dimensions.height;
|
||||
const label = getDatedBarcodeLabelData();
|
||||
const productionDate = document.getElementById('datedBarcodeProductionDate').value || '';
|
||||
const expiryDate = document.getElementById('datedBarcodeExpiryDate').value || '';
|
||||
|
||||
if (!label) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!productionDate || !expiryDate) {
|
||||
Swal.fire('Missing dates', 'Please select both production and expiry dates before printing.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (expiryDate < productionDate) {
|
||||
Swal.fire('Invalid dates', 'Expiry date must be the same as or later than the production date.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const nameHtml = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn);
|
||||
const dateHtml = buildDatedBarcodeDateRowsHtml(productionDate, expiryDate);
|
||||
const priceHtml = label.price ? `<div class="label-price">OMR ${escapeBarcodeLabelHtml(label.price)}</div>` : '';
|
||||
const svg = buildDatedBarcodeSvgMarkup(label.sku, width, height);
|
||||
const compactClass = width <= 40 || height <= 30 ? 'label-compact' : '';
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.style.position = 'absolute';
|
||||
iframe.style.width = '0px';
|
||||
iframe.style.height = '0px';
|
||||
iframe.style.border = 'none';
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
const doc = iframe.contentWindow.document;
|
||||
|
||||
let labelsHtml = '';
|
||||
for (let i = 0; i < qty; i++) {
|
||||
labelsHtml += `
|
||||
<div class="label-container dated-label ${compactClass}">
|
||||
${nameHtml ? `<div class="label-name">${nameHtml}</div>` : ''}
|
||||
<div class="barcode-wrap">${svg}</div>
|
||||
<div class="label-meta">
|
||||
<div class="label-dates">${dateHtml}</div>
|
||||
${priceHtml}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
doc.open();
|
||||
doc.write(`
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
@page { size: ${width}mm ${height}mm; margin: 0; }
|
||||
body { margin: 0; padding: 0; font-family: sans-serif; }
|
||||
.label-container {
|
||||
width: ${width}mm;
|
||||
height: ${height}mm;
|
||||
page-break-after: always;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.label-container:last-child { page-break-after: avoid; }
|
||||
.dated-label {
|
||||
padding: 0.78mm 1.25mm 0.8mm;
|
||||
gap: 0.2mm;
|
||||
}
|
||||
.label-name {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
line-height: 1;
|
||||
}
|
||||
.label-name-ar,
|
||||
.label-name-en {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.label-name-ar {
|
||||
font-weight: 700;
|
||||
font-size: 13px;
|
||||
direction: rtl;
|
||||
}
|
||||
.label-name-en {
|
||||
font-size: 10.6px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.label-meta {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.15mm;
|
||||
margin-top: 0;
|
||||
}
|
||||
.label-dates {
|
||||
--label-date-row-gap: 1.2mm;
|
||||
--label-date-item-gap: 0.55mm;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
direction: ltr;
|
||||
font-size: 10.1px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
}
|
||||
.label-date-row {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
}
|
||||
.label-date-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.label-date-key {
|
||||
font-weight: 700;
|
||||
}
|
||||
.label-price {
|
||||
font-size: 11.2px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.label-compact {
|
||||
padding: 0.58mm 0.95mm 0.6mm;
|
||||
gap: 0.15mm;
|
||||
}
|
||||
.label-compact .label-name-ar { font-size: 11.1px; }
|
||||
.label-compact .label-name-en { font-size: 9.1px; }
|
||||
.label-compact .label-meta { gap: 0.12mm; }
|
||||
.label-compact .label-dates {
|
||||
--label-date-row-gap: 0.85mm;
|
||||
--label-date-item-gap: 0.35mm;
|
||||
font-size: 8.7px;
|
||||
}
|
||||
.label-compact .label-price { font-size: 9.7px; }
|
||||
.barcode-wrap {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 0.55mm;
|
||||
margin: 0.08mm 0;
|
||||
overflow: visible;
|
||||
}
|
||||
.barcode-wrap svg {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
overflow: visible;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${labelsHtml}
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
doc.close();
|
||||
|
||||
iframe.contentWindow.focus();
|
||||
setTimeout(() => {
|
||||
iframe.contentWindow.print();
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(iframe);
|
||||
}, 2000);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
|
||||
window.printPosReceiptFromInvoice = function(inv) {
|
||||
const container = document.getElementById('posReceiptContent');
|
||||
const itemsHtml = inv.items.map(item => {
|
||||
const itemTotal = item.unit_price * item.quantity;
|
||||
const vatRate = parseFloat(item.vat_rate !== undefined && item.vat_rate !== null ? item.vat_rate : 0);
|
||||
const vatAmount = itemTotal * (vatRate / (100 + vatRate));
|
||||
return `
|
||||
<tr>
|
||||
<td>${item.name_en} / ${item.name_ar}<br><small>${item.quantity} x ${parseFloat(item.unit_price).toFixed(3)}</small></td>
|
||||
<td style="text-align: right; vertical-align: bottom;">${vatAmount.toFixed(2)}</td>
|
||||
<td style="text-align: right; vertical-align: bottom;">${itemTotal.toFixed(3)}</td>
|
||||
</tr>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
const totalVat = inv.items.reduce((sum, item) => {
|
||||
const itemTotal = item.unit_price * item.quantity;
|
||||
const vatRate = parseFloat(item.vat_rate !== undefined && item.vat_rate !== null ? item.vat_rate : 0);
|
||||
return sum + (itemTotal * (vatRate / (100 + vatRate)));
|
||||
}, 0);
|
||||
const subtotal = inv.items.reduce((sum, item) => sum + (item.unit_price * item.quantity), 0);
|
||||
|
||||
const companyName = "<?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?>";
|
||||
const outletName = "<?= htmlspecialchars($data['settings']['current_outlet_name'] ?? '') ?>";
|
||||
const companyPhone = "<?= htmlspecialchars($data['settings']['company_phone'] ?? '') ?>";
|
||||
const companyVat = "<?= htmlspecialchars($data['settings']['vat_number'] ?? '') ?>";
|
||||
const companyLogo = "<?= htmlspecialchars($data['settings']['company_logo'] ?? '') ?>";
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="thermal-receipt">
|
||||
<div class="center">
|
||||
${companyLogo ? `<img src="${companyLogo}" alt="Logo" style="max-height: 60px; width: auto; margin-bottom: 10px; display: block; margin-left: auto; margin-right: auto;">` : ''}
|
||||
<h5 class="mb-0 fw-bold">${companyName}</h5>
|
||||
${inv.outlet_name ? `<div class="fw-bold text-uppercase">${inv.outlet_name}</div>` : ''}
|
||||
${companyPhone ? `<div>Tel: ${companyPhone}</div>` : ''}
|
||||
${companyVat ? `<div>VAT: ${companyVat}</div>` : ''}
|
||||
<div class="separator"></div>
|
||||
<h6 class="fw-bold">TAX INVOICE / فاتورة ضريبية</h6>
|
||||
<div>Inv / رقم: INV-${inv.id.toString().padStart(5, '0')}</div>
|
||||
<div>Date / التاريخ: ${inv.invoice_date}</div>
|
||||
<div class="separator"></div>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Customer / العميل:</strong> ${inv.customer_name || 'Walk-in / عميل عابر'}
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ITEM / الصنف</th>
|
||||
<th style="text-align: right;">VAT / الضريبة</th>
|
||||
<th style="text-align: right;">TOTAL / الإجمالي</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${itemsHtml}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="separator"></div>
|
||||
<div class="d-flex justify-content-between small">
|
||||
<span>Subtotal (Excl. VAT) / المجموع الفرعي (دون الضريبة)</span>
|
||||
<span><?= __('currency') ?> ${(subtotal - totalVat).toFixed(3)}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between small">
|
||||
<span>VAT / الضريبة</span>
|
||||
<span><?= __('currency') ?> ${totalVat.toFixed(2)}</span>
|
||||
</div>
|
||||
<div class="total-row d-flex justify-content-between">
|
||||
<span>TOTAL (Incl. VAT) / الإجمالي (شامل الضريبة)</span>
|
||||
<span><?= __('currency') ?> ${subtotal.toFixed(3)}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between small">
|
||||
<span>PAID / المدفوع</span>
|
||||
<span><?= __('currency') ?> ${parseFloat(inv.paid_amount).toFixed(3)}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between small fw-bold">
|
||||
<span>BALANCE / الرصيد</span>
|
||||
<span><?= __('currency') ?> ${(subtotal - inv.paid_amount).toFixed(3)}</span>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="center small">
|
||||
<p>Thank You for your business! / شكراً لتعاملكم معنا!</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const posModal = new bootstrap.Modal(document.getElementById('posReceiptModal'));
|
||||
posModal.show();
|
||||
};
|
||||
|
||||
function printPosReceipt() {
|
||||
const content = document.getElementById('posReceiptContent').innerHTML;
|
||||
const printArea = document.getElementById('posPrintArea');
|
||||
printArea.innerHTML = `<div class="thermal-receipt thermal-receipt-print">${content}</div>`;
|
||||
|
||||
document.body.classList.add('printing-receipt');
|
||||
window.print();
|
||||
document.body.classList.remove('printing-receipt');
|
||||
location.reload();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user