add date barcode
This commit is contained in:
parent
8fccefd923
commit
d52dfbe9df
62
index.php
62
index.php
@ -7277,11 +7277,20 @@ runtime_debug_mark('page:rendering', ['page' => (string)$page]);
|
|||||||
</td>
|
</td>
|
||||||
<td><?= !empty($item['expiry_date']) ? htmlspecialchars((string)$item['expiry_date']) : '---' ?></td>
|
<td><?= !empty($item['expiry_date']) ? htmlspecialchars((string)$item['expiry_date']) : '---' ?></td>
|
||||||
<td><?= number_format((float)$item['vat_rate'], 2) ?>%</td>
|
<td><?= number_format((float)$item['vat_rate'], 2) ?>%</td>
|
||||||
|
<?php
|
||||||
|
$itemBarcodePrice = number_format((float)$item['sale_price'] * (1 + (float)($item['vat_rate'] ?? 0) / 100), 3);
|
||||||
|
$itemSkuJs = htmlspecialchars(json_encode((string)($item['sku'] ?? ''), JSON_UNESCAPED_UNICODE), ENT_QUOTES, 'UTF-8');
|
||||||
|
$itemNameArJs = htmlspecialchars(json_encode((string)($item['name_ar'] ?? ''), JSON_UNESCAPED_UNICODE), ENT_QUOTES, 'UTF-8');
|
||||||
|
$itemNameEnJs = htmlspecialchars(json_encode((string)($item['name_en'] ?? ''), JSON_UNESCAPED_UNICODE), ENT_QUOTES, 'UTF-8');
|
||||||
|
$itemBarcodePriceJs = htmlspecialchars(json_encode((string)$itemBarcodePrice, JSON_UNESCAPED_UNICODE), ENT_QUOTES, 'UTF-8');
|
||||||
|
$itemExpiryDateJs = htmlspecialchars(json_encode(!empty($item['expiry_date']) ? (string)$item['expiry_date'] : '', JSON_UNESCAPED_UNICODE), ENT_QUOTES, 'UTF-8');
|
||||||
|
?>
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group btn-group-sm">
|
<div class="btn-group btn-group-sm">
|
||||||
<button class="btn btn-outline-info" title="View" data-bs-toggle="modal" data-bs-target="#viewItemModal<?= $item['id'] ?>"><i class="bi bi-eye"></i></button>
|
<button class="btn btn-outline-info" title="View" data-bs-toggle="modal" data-bs-target="#viewItemModal<?= $item['id'] ?>"><i class="bi bi-eye"></i></button>
|
||||||
<button class="btn btn-outline-primary" title="Edit" data-bs-toggle="modal" data-bs-target="#editItemModal<?= $item['id'] ?>"><i class="bi bi-pencil"></i></button>
|
<button class="btn btn-outline-primary" title="Edit" data-bs-toggle="modal" data-bs-target="#editItemModal<?= $item['id'] ?>"><i class="bi bi-pencil"></i></button>
|
||||||
<button class="btn btn-outline-dark" title="Barcode" onclick="printItemBarcode('<?= htmlspecialchars($item['sku']) ?>', '<?= htmlspecialchars($item['name_ar']) ?>', '<?= htmlspecialchars($item['name_en']) ?>', '<?= number_format((float)$item['sale_price'] * (1 + (float)($item['vat_rate'] ?? 0) / 100), 3) ?>')"><i class="bi bi-upc"></i></button>
|
<button class="btn btn-outline-dark" title="Barcode" onclick="printItemBarcode(<?= $itemSkuJs ?>, <?= $itemNameArJs ?>, <?= $itemNameEnJs ?>, <?= $itemBarcodePriceJs ?>)"><i class="bi bi-upc"></i></button>
|
||||||
|
<button class="btn btn-outline-secondary" title="Barcode + Dates" onclick="printItemBarcodeWithDates(<?= $itemSkuJs ?>, <?= $itemNameArJs ?>, <?= $itemNameEnJs ?>, <?= $itemExpiryDateJs ?>)"><i class="bi bi-calendar-date"></i></button>
|
||||||
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
|
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
|
||||||
<input type="hidden" name="id" value="<?= $item['id'] ?>">
|
<input type="hidden" name="id" value="<?= $item['id'] ?>">
|
||||||
<button type="submit" name="delete_item" class="btn btn-outline-danger" title="Delete"><i class="bi bi-trash"></i></button>
|
<button type="submit" name="delete_item" class="btn btn-outline-danger" title="Delete"><i class="bi bi-trash"></i></button>
|
||||||
@ -7318,7 +7327,8 @@ runtime_debug_mark('page:rendering', ['page' => (string)$page]);
|
|||||||
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button class="btn btn-outline-dark" onclick="printItemBarcode('<?= htmlspecialchars($item['sku']) ?>', '<?= htmlspecialchars($item['name_ar']) ?>', '<?= htmlspecialchars($item['name_en']) ?>', '<?= number_format((float)$item['sale_price'] * (1 + (float)($item['vat_rate'] ?? 0) / 100), 3) ?>')"><i class="bi bi-printer"></i> Print Barcode</button>
|
<button class="btn btn-outline-dark" onclick="printItemBarcode(<?= $itemSkuJs ?>, <?= $itemNameArJs ?>, <?= $itemNameEnJs ?>, <?= $itemBarcodePriceJs ?>)"><i class="bi bi-printer"></i> Print Barcode</button>
|
||||||
|
<button class="btn btn-outline-secondary" onclick="printItemBarcodeWithDates(<?= $itemSkuJs ?>, <?= $itemNameArJs ?>, <?= $itemNameEnJs ?>, <?= $itemExpiryDateJs ?>)"><i class="bi bi-calendar-date"></i> Barcode + Dates</button>
|
||||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Close" data-ar="إغلاق">Close</button>
|
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Close" data-ar="إغلاق">Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -12223,6 +12233,54 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Barcode + Dates Print Modal -->
|
||||||
|
<div class="modal fade" id="datedBarcodePrintModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content border-0 shadow">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Print Barcode + Dates Label</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body text-center">
|
||||||
|
<div id="datedBarcodeContainer" class="p-3 bg-white border mb-3 mx-auto" style="width: fit-content; max-width: 100%;">
|
||||||
|
<div id="datedBarcodeLabelName" class="fw-bold small mb-1"></div>
|
||||||
|
<svg id="datedBarcodeSvg" style="max-width: 100%; height: auto;"></svg>
|
||||||
|
<div id="datedBarcodeLabelDates" class="small mt-2 text-start mx-auto" style="width: fit-content; min-width: 145px;"></div>
|
||||||
|
</div>
|
||||||
|
<div class="row g-2 mb-3 text-start">
|
||||||
|
<div class="col-6">
|
||||||
|
<label class="form-label small" data-en="Production Date" data-ar="تاريخ الإنتاج">Production Date</label>
|
||||||
|
<input type="date" id="datedBarcodeProductionDate" class="form-control form-control-sm">
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<label class="form-label small" data-en="Expiry Date" data-ar="تاريخ الانتهاء">Expiry Date</label>
|
||||||
|
<input type="date" id="datedBarcodeExpiryDate" class="form-control form-control-sm">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label small">Number of Labels</label>
|
||||||
|
<input type="number" id="datedBarcodeQty" class="form-control form-control-sm mx-auto" value="1" min="1" style="width: 80px;">
|
||||||
|
</div>
|
||||||
|
<div class="row mb-2 mx-auto" style="max-width: 200px;">
|
||||||
|
<div class="col-6">
|
||||||
|
<label class="form-label small">Width (mm)</label>
|
||||||
|
<input type="number" id="datedBarcodeWidth" class="form-control form-control-sm" value="50" min="10">
|
||||||
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<label class="form-label small">Height (mm)</label>
|
||||||
|
<input type="number" id="datedBarcodeHeight" class="form-control form-control-sm" value="35" min="10">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-text text-center mb-1">For barcode labels with P / E dates, 50 × 35 mm or larger is recommended.</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Close" data-ar="إغلاق">Close</button>
|
||||||
|
<button type="button" class="btn btn-primary" onclick="executeDatedBarcodePrint()"><i class="bi bi-printer me-2"></i>Print Now</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Avery Labels Modal -->
|
<!-- Avery Labels Modal -->
|
||||||
<div class="modal fade" id="averyLabelsModal" tabindex="-1">
|
<div class="modal fade" id="averyLabelsModal" tabindex="-1">
|
||||||
<div class="modal-dialog modal-xl">
|
<div class="modal-dialog modal-xl">
|
||||||
|
|||||||
@ -18,6 +18,19 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
function getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm) {
|
||||||
const skuText = String(sku || '');
|
const skuText = String(sku || '');
|
||||||
const skuLength = skuText.length;
|
const skuLength = skuText.length;
|
||||||
@ -77,10 +90,14 @@
|
|||||||
|
|
||||||
function buildSingleBarcodeSvgMarkup(sku, labelWidthMm, labelHeightMm) {
|
function buildSingleBarcodeSvgMarkup(sku, labelWidthMm, labelHeightMm) {
|
||||||
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||||
|
const scale = getSingleBarcodeScale(labelWidthMm, labelHeightMm);
|
||||||
JsBarcode(svg, sku, getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm));
|
JsBarcode(svg, sku, getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm));
|
||||||
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
||||||
svg.style.width = '100%';
|
svg.style.width = Math.round(scale * 100) + '%';
|
||||||
|
svg.style.maxWidth = '100%';
|
||||||
svg.style.height = 'auto';
|
svg.style.height = 'auto';
|
||||||
|
svg.style.display = 'block';
|
||||||
|
svg.style.margin = '0 auto';
|
||||||
return svg.outerHTML;
|
return svg.outerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,6 +110,7 @@
|
|||||||
const dimensions = getSingleBarcodePrintDimensions();
|
const dimensions = getSingleBarcodePrintDimensions();
|
||||||
const width = dimensions.width;
|
const width = dimensions.width;
|
||||||
const height = dimensions.height;
|
const height = dimensions.height;
|
||||||
|
const scale = getSingleBarcodeScale(width, height);
|
||||||
const nameContainer = document.getElementById('barcodeLabelName');
|
const nameContainer = document.getElementById('barcodeLabelName');
|
||||||
const priceContainer = document.getElementById('barcodeLabelPrice');
|
const priceContainer = document.getElementById('barcodeLabelPrice');
|
||||||
const previewContainer = document.getElementById('barcodeContainer');
|
const previewContainer = document.getElementById('barcodeContainer');
|
||||||
@ -104,15 +122,18 @@
|
|||||||
|
|
||||||
nameContainer.innerHTML = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn);
|
nameContainer.innerHTML = buildSingleBarcodeNameHtml(label.nameAr, label.nameEn);
|
||||||
priceContainer.textContent = label.price ? 'OMR ' + label.price : '';
|
priceContainer.textContent = label.price ? 'OMR ' + label.price : '';
|
||||||
previewContainer.style.width = Math.min(Math.max(width * 4, 180), 320) + 'px';
|
previewContainer.style.width = Math.min(Math.max(width * 3.6, 170), 280) + 'px';
|
||||||
previewContainer.style.maxWidth = '100%';
|
previewContainer.style.maxWidth = '100%';
|
||||||
previewContainer.style.padding = height <= 25 ? '12px' : '16px';
|
previewContainer.style.padding = height <= 25 ? '12px' : '16px';
|
||||||
|
|
||||||
svg.innerHTML = '';
|
svg.innerHTML = '';
|
||||||
JsBarcode(svg, label.sku, getSingleBarcodeOptions(label.sku, width, height));
|
JsBarcode(svg, label.sku, getSingleBarcodeOptions(label.sku, width, height));
|
||||||
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
||||||
svg.style.width = '100%';
|
svg.style.width = Math.round(scale * 100) + '%';
|
||||||
|
svg.style.maxWidth = '100%';
|
||||||
svg.style.height = 'auto';
|
svg.style.height = 'auto';
|
||||||
|
svg.style.display = 'block';
|
||||||
|
svg.style.margin = '0 auto';
|
||||||
}
|
}
|
||||||
|
|
||||||
function initSingleBarcodePreviewControls() {
|
function initSingleBarcodePreviewControls() {
|
||||||
@ -272,6 +293,309 @@
|
|||||||
}, 500);
|
}, 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"><span class="label-date-key">P:</span><span class="label-date-value">${escapeBarcodeLabelHtml(productionText)}</span></div>
|
||||||
|
<div class="label-date-row"><span class="label-date-key">E:</span><span class="label-date-value">${escapeBarcodeLabelHtml(expiryText)}</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.88;
|
||||||
|
}
|
||||||
|
if (labelWidthMm <= 40 || labelHeightMm <= 30) {
|
||||||
|
return 0.84;
|
||||||
|
}
|
||||||
|
if (labelWidthMm <= 50 || labelHeightMm <= 35) {
|
||||||
|
return 0.80;
|
||||||
|
}
|
||||||
|
return 0.76;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDatedBarcodeOptions(sku, labelWidthMm, labelHeightMm) {
|
||||||
|
const baseOptions = getSingleBarcodeOptions(sku, labelWidthMm, labelHeightMm);
|
||||||
|
const skuLength = String(sku || '').length;
|
||||||
|
const showValue = labelHeightMm >= 42 && labelWidthMm >= 50 && skuLength <= 16;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...baseOptions,
|
||||||
|
displayValue: showValue,
|
||||||
|
fontSize: showValue ? 9 : 8,
|
||||||
|
textMargin: showValue ? 2 : 0,
|
||||||
|
height: Math.max(Math.round(baseOptions.height * (showValue ? 0.78 : 0.86)), 24),
|
||||||
|
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.style.width = Math.round(scale * 100) + '%';
|
||||||
|
svg.style.maxWidth = '100%';
|
||||||
|
svg.style.height = 'auto';
|
||||||
|
svg.style.display = 'block';
|
||||||
|
svg.style.margin = '0 auto';
|
||||||
|
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 nameContainer = document.getElementById('datedBarcodeLabelName');
|
||||||
|
const datesContainer = document.getElementById('datedBarcodeLabelDates');
|
||||||
|
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);
|
||||||
|
datesContainer.innerHTML = buildDatedBarcodeDateRowsHtml(
|
||||||
|
productionInput ? productionInput.value : '',
|
||||||
|
expiryInput ? expiryInput.value : ''
|
||||||
|
);
|
||||||
|
previewContainer.style.width = Math.min(Math.max(width * 3.8, 180), 300) + 'px';
|
||||||
|
previewContainer.style.maxWidth = '100%';
|
||||||
|
previewContainer.style.padding = height <= 30 ? '10px 12px' : '12px 14px';
|
||||||
|
|
||||||
|
svg.innerHTML = '';
|
||||||
|
JsBarcode(svg, label.sku, getDatedBarcodeOptions(label.sku, width, height));
|
||||||
|
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
||||||
|
svg.style.width = Math.round(scale * 100) + '%';
|
||||||
|
svg.style.maxWidth = '100%';
|
||||||
|
svg.style.height = 'auto';
|
||||||
|
svg.style.display = 'block';
|
||||||
|
svg.style.margin = '0 auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
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, defaultExpiryDate) {
|
||||||
|
if (!sku) {
|
||||||
|
Swal.fire('Error', 'This item has no SKU/Barcode assigned.', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.currentDatedBarcodeLabel = {
|
||||||
|
sku: String(sku),
|
||||||
|
nameAr: nameAr || '',
|
||||||
|
nameEn: nameEn || ''
|
||||||
|
};
|
||||||
|
|
||||||
|
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 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-dates">${dateHtml}</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: space-between;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.label-container:last-child { page-break-after: avoid; }
|
||||||
|
.dated-label {
|
||||||
|
padding: 1.2mm 2mm;
|
||||||
|
gap: 0.6mm;
|
||||||
|
}
|
||||||
|
.label-name {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
line-height: 1.05;
|
||||||
|
}
|
||||||
|
.label-name-ar,
|
||||||
|
.label-name-en {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.label-name-ar {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 10px;
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
.label-name-en { font-size: 8px; }
|
||||||
|
.label-dates {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.35mm;
|
||||||
|
font-size: 8px;
|
||||||
|
line-height: 1.05;
|
||||||
|
}
|
||||||
|
.label-date-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1mm;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.label-date-key {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.label-compact {
|
||||||
|
padding: 0.9mm 1.4mm;
|
||||||
|
gap: 0.45mm;
|
||||||
|
}
|
||||||
|
.label-compact .label-name-ar { font-size: 9px; }
|
||||||
|
.label-compact .label-name-en { font-size: 7px; }
|
||||||
|
.label-compact .label-dates { font-size: 7px; }
|
||||||
|
.barcode-wrap {
|
||||||
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 1.2mm;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.barcode-wrap svg {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
${labelsHtml}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`);
|
||||||
|
doc.close();
|
||||||
|
|
||||||
|
iframe.contentWindow.focus();
|
||||||
|
setTimeout(() => {
|
||||||
|
iframe.contentWindow.print();
|
||||||
|
setTimeout(() => {
|
||||||
|
document.body.removeChild(iframe);
|
||||||
|
}, 2000);
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
|
||||||
<?php require 'pages/sales_purchases_print_script.php'; ?>
|
<?php require 'pages/sales_purchases_print_script.php'; ?>
|
||||||
|
|
||||||
window.printPosReceiptFromInvoice = function(inv) {
|
window.printPosReceiptFromInvoice = function(inv) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user