Autosave: 20260423-152803
This commit is contained in:
parent
9b5e175eec
commit
ec5e25fdd0
386
print_label_dates.php
Normal file
386
print_label_dates.php
Normal file
@ -0,0 +1,386 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/includes/app.php';
|
||||
require_permission('stock', 'show');
|
||||
|
||||
$pdo = db();
|
||||
$items = [];
|
||||
|
||||
$skus = [];
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['skus'])) {
|
||||
$skus = is_array($_POST['skus']) ? $_POST['skus'] : explode(',', $_POST['skus']);
|
||||
$skus = array_values(array_filter(array_map('trim', $skus)));
|
||||
} elseif (!empty($_GET['sku'])) {
|
||||
$skus = [$_GET['sku']];
|
||||
}
|
||||
|
||||
if (!empty($skus)) {
|
||||
$placeholders = str_repeat('?,', count($skus) - 1) . '?';
|
||||
$stmt = $pdo->prepare("SELECT * FROM items WHERE sku IN ($placeholders)");
|
||||
$stmt->execute($skus);
|
||||
$results = $stmt->fetchAll();
|
||||
// Index by SKU
|
||||
foreach ($results as $row) {
|
||||
$items[$row['sku']] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
$customWidth = $_REQUEST['custom_width'] ?? '40';
|
||||
$customHeight = $_REQUEST['custom_height'] ?? '25';
|
||||
|
||||
// Templates configuration
|
||||
$templates = [
|
||||
'custom_roll' => [
|
||||
'name' => 'Custom Size / مقاس مخصص (أدخل المقاس أدناه)',
|
||||
'cols' => 1,
|
||||
'rows' => 1,
|
||||
'width' => $customWidth . 'mm',
|
||||
'height' => $customHeight . 'mm',
|
||||
'margin_top' => '0mm',
|
||||
'margin_left' => '0mm',
|
||||
'gap_x' => '0mm',
|
||||
'gap_y' => '0mm',
|
||||
'page_width' => $customWidth . 'mm',
|
||||
'page_height' => $customHeight . 'mm',
|
||||
],
|
||||
'roll_40x25' => [
|
||||
'name' => 'Roll / Zebra (40 x 25 mm)',
|
||||
'cols' => 1,
|
||||
'rows' => 1,
|
||||
'width' => '40mm',
|
||||
'height' => '25mm',
|
||||
'margin_top' => '0mm',
|
||||
'margin_left' => '0mm',
|
||||
'gap_x' => '0mm',
|
||||
'gap_y' => '0mm',
|
||||
'page_width' => '40mm',
|
||||
'page_height' => '25mm',
|
||||
],
|
||||
'roll_25x40' => [
|
||||
'name' => 'Roll / Zebra (25 x 40 mm)',
|
||||
'cols' => 1,
|
||||
'rows' => 1,
|
||||
'width' => '25mm',
|
||||
'height' => '40mm',
|
||||
'margin_top' => '0mm',
|
||||
'margin_left' => '0mm',
|
||||
'gap_x' => '0mm',
|
||||
'gap_y' => '0mm',
|
||||
'page_width' => '25mm',
|
||||
'page_height' => '40mm',
|
||||
],
|
||||
'roll_38x25' => [
|
||||
'name' => 'Roll / Zebra (38 x 25 mm)',
|
||||
'cols' => 1,
|
||||
'rows' => 1,
|
||||
'width' => '38mm',
|
||||
'height' => '25mm',
|
||||
'margin_top' => '0mm',
|
||||
'margin_left' => '0mm',
|
||||
'gap_x' => '0mm',
|
||||
'gap_y' => '0mm',
|
||||
'page_width' => '38mm',
|
||||
'page_height' => '25mm',
|
||||
],
|
||||
'avery_65' => [
|
||||
'name' => 'Avery L7651 - 65 Labels (38.1 x 21.2 mm)',
|
||||
'cols' => 5,
|
||||
'rows' => 13,
|
||||
'width' => '38.1mm',
|
||||
'height' => '21.2mm',
|
||||
'margin_top' => '10.5mm',
|
||||
'margin_left' => '4.7mm',
|
||||
'gap_x' => '2.5mm',
|
||||
'gap_y' => '0mm',
|
||||
'page_width' => '210mm',
|
||||
'page_height' => '297mm',
|
||||
],
|
||||
'avery_54' => [
|
||||
'name' => 'Avery 54 Labels (32 x 25.4 mm)',
|
||||
'cols' => 6,
|
||||
'rows' => 9,
|
||||
'width' => '32mm',
|
||||
'height' => '25.4mm',
|
||||
'margin_top' => '10mm',
|
||||
'margin_left' => '5mm',
|
||||
'gap_x' => '2mm',
|
||||
'gap_y' => '0mm',
|
||||
'page_width' => '210mm',
|
||||
'page_height' => '297mm',
|
||||
],
|
||||
'avery_45' => [
|
||||
'name' => 'Avery 45 Labels (38.1 x 29.6 mm)',
|
||||
'cols' => 5,
|
||||
'rows' => 9,
|
||||
'width' => '38.1mm',
|
||||
'height' => '29.6mm',
|
||||
'margin_top' => '15mm',
|
||||
'margin_left' => '5mm',
|
||||
'gap_x' => '2mm',
|
||||
'gap_y' => '0mm',
|
||||
'page_width' => '210mm',
|
||||
'page_height' => '297mm',
|
||||
]
|
||||
];
|
||||
|
||||
$templateId = $_REQUEST['template'] ?? 'custom_roll';
|
||||
$tpl = $templates[$templateId] ?? $templates['custom_roll'];
|
||||
|
||||
$pageWidth = $tpl['page_width'] ?? '210mm';
|
||||
$pageHeight = $tpl['page_height'] ?? '297mm';
|
||||
$pageCssSize = (isset($tpl['page_width']) && $tpl['page_width'] !== '210mm') ? "{$tpl['page_width']} {$tpl['page_height']}" : "A4 portrait";
|
||||
|
||||
if ($templateId !== 'custom_roll') {
|
||||
$customWidth = floatval(str_replace('mm', '', $tpl['width']));
|
||||
$customHeight = floatval(str_replace('mm', '', $tpl['height']));
|
||||
}
|
||||
|
||||
// Prepare labels to print
|
||||
$labelsToPrint = [];
|
||||
if (!empty($items)) {
|
||||
// Check if quantities are posted
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['qty'])) {
|
||||
foreach ($_POST['qty'] as $sku => $qty) {
|
||||
if (isset($items[$sku])) {
|
||||
for ($i = 0; $i < (int)$qty; $i++) {
|
||||
$itemData = $items[$sku];
|
||||
$itemData['prod_date'] = $_POST['prod_date'][$sku] ?? date('Y-m');
|
||||
$itemData['exp_date'] = $_POST['exp_date'][$sku] ?? date('Y-m', strtotime('+1 year'));
|
||||
$labelsToPrint[] = $itemData;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Default 1 per item
|
||||
foreach ($skus as $sku) {
|
||||
if (isset($items[$sku])) {
|
||||
$itemData = $items[$sku];
|
||||
$itemData['prod_date'] = date('Y-m');
|
||||
$itemData['exp_date'] = date('Y-m', strtotime('+1 year'));
|
||||
$labelsToPrint[] = $itemData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$isSinglePrint = isset($_GET['sku']) && count($skus) === 1;
|
||||
$companyName = current_lang() === 'ar' ? get_setting('company_name_ar', 'حلوى الريامي') : get_setting('company_name_en', 'Al Riyami Sweets');
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?= current_lang() ?>" dir="<?= current_lang() === 'ar' ? 'rtl' : 'ltr' ?>">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title><?= h(tr('طباعة ملصقات مع التواريخ', 'Print Labels with Dates')) ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.5/dist/JsBarcode.all.min.js"></script>
|
||||
<style>
|
||||
body { background: #f0f2f5; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
|
||||
.no-print { display: block; }
|
||||
.print-only { display: none; }
|
||||
|
||||
.page {
|
||||
width: <?= $pageWidth ?>;
|
||||
height: <?= $pageHeight ?>;
|
||||
padding-top: <?= $tpl['margin_top'] ?>;
|
||||
padding-left: <?= $tpl['margin_left'] ?>;
|
||||
padding-right: <?= $tpl['margin_left'] ?>;
|
||||
margin: 10mm auto;
|
||||
border: 1px solid #D3D3D3;
|
||||
border-radius: 5px;
|
||||
background: white;
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(<?= $tpl['cols'] ?>, <?= $tpl['width'] ?>);
|
||||
grid-auto-rows: <?= $tpl['height'] ?>;
|
||||
column-gap: <?= $tpl['gap_x'] ?>;
|
||||
row-gap: <?= $tpl['gap_y'] ?>;
|
||||
box-sizing: border-box;
|
||||
page-break-after: always;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.label-item {
|
||||
width: <?= $tpl['width'] ?>;
|
||||
height: <?= $tpl['height'] ?>;
|
||||
border: 1px dashed #ccc;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
padding: 2px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.label-company { font-size: 9px; font-weight: bold; margin-bottom: 1px; text-transform: uppercase; }
|
||||
.label-name { font-size: 9px; font-weight: bold; line-height: 1.1; margin-bottom: 2px; max-height: 20px; overflow: hidden; }
|
||||
.label-price { font-size: 10px; font-weight: bold; margin-top: 1px; }
|
||||
.label-sku { font-size: 8px; color: #555; }
|
||||
.label-dates { font-size: 7.5px; font-weight: bold; margin-top: 1px; color: #111; letter-spacing: 0.2px; }
|
||||
.label-barcode { margin: 0; display: flex; align-items: center; justify-content: center; }
|
||||
.label-barcode svg { width: 100%; height: 100%; max-height: 14px; }
|
||||
|
||||
@media print {
|
||||
@page { size: <?= $pageCssSize ?>; margin: 0; }
|
||||
html, body {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
background: white;
|
||||
height: 100%;
|
||||
}
|
||||
.no-print { display: none !important; }
|
||||
.print-only { display: block; }
|
||||
|
||||
.print-preview { margin: 0 !important; padding: 0 !important; border: none !important; }
|
||||
|
||||
.page {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
border: none !important;
|
||||
width: <?= $pageWidth ?> !important;
|
||||
height: <?= $pageHeight ?> !important;
|
||||
box-shadow: none !important;
|
||||
background: white !important;
|
||||
page-break-after: auto !important;
|
||||
page-break-inside: avoid !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
.page + .page {
|
||||
page-break-before: always !important;
|
||||
}
|
||||
.label-item { border: none !important; margin: 0; padding: 2px; box-sizing: border-box; }
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container mt-4 no-print">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0"><?= h(tr('إعدادات الطباعة', 'Print Settings')) ?></h5>
|
||||
<a href="stock.php" class="btn btn-sm btn-light"><?= h(tr('رجوع للمخزون', 'Back to Stock')) ?></a>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST">
|
||||
<div class="row g-3 align-items-end mb-3">
|
||||
<input type="hidden" name="template" value="custom_roll">
|
||||
<div class="col-md-2 col-6">
|
||||
<label class="form-label fw-bold"><?= h(tr('العرض', 'Width')) ?> (mm)</label>
|
||||
<input type="number" name="custom_width" class="form-control" value="<?= h($customWidth) ?>" onchange="this.form.submit()" min="10">
|
||||
</div>
|
||||
<div class="col-md-2 col-6">
|
||||
<label class="form-label fw-bold"><?= h(tr('الارتفاع', 'Height')) ?> (mm)</label>
|
||||
<input type="number" name="custom_height" class="form-control" value="<?= h($customHeight) ?>" onchange="this.form.submit()" min="10">
|
||||
</div>
|
||||
|
||||
<div class="col-md-auto text-end flex-grow-1">
|
||||
<button type="button" class="btn btn-success btn-lg shadow" onclick="window.print()">
|
||||
<i class="bi bi-printer"></i> <?= h(tr('طباعة الآن', 'Print Now')) ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive border rounded">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>SKU</th>
|
||||
<th><?= h(tr('الصنف', 'Item')) ?></th>
|
||||
<th><?= h(tr('السعر', 'Price')) ?></th>
|
||||
<th width="150" class="text-center"><?= h(tr('عدد الملصقات', 'Labels Count')) ?></th>
|
||||
<th width="80" class="text-center"><?= h(tr('إزالة', 'Remove')) ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($items as $sku => $item):
|
||||
?><tr>
|
||||
<td class="fw-bold text-secondary">
|
||||
<?= h($sku) ?>
|
||||
<input type="hidden" name="skus[]" value="<?= h($sku) ?>">
|
||||
</td>
|
||||
<td><?= h($item['name']) ?></td>
|
||||
<td><span class="badge bg-light text-dark border"><?= h(currency($item['price'])) ?></span></td>
|
||||
<td>
|
||||
<input type="number" name="qty[<?= h($sku) ?>]" class="form-control text-center" value="<?= isset($_POST['qty'][$sku]) ? (int)$_POST['qty'][$sku] : 1 ?>" min="1">
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<button type="button" class="btn btn-sm btn-outline-danger rounded-circle" onclick="this.closest('tr').remove();" title="<?= h(tr('إزالة', 'Remove')) ?>">
|
||||
<i class="bi bi-x-lg"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if(empty($items)):
|
||||
?><tr>
|
||||
<td colspan="7" class="text-center text-muted py-4">
|
||||
<i class="bi bi-inbox fs-3 d-block mb-2"></i>
|
||||
<?= h(tr('لم يتم تحديد أصناف', 'No items selected')) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php if(!empty($items)):
|
||||
?><div class="mt-3">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-arrow-clockwise"></i> <?= h(tr('تحديث المعاينة', 'Update Preview')) ?>
|
||||
</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($labelsToPrint)): ?>
|
||||
<div class="print-preview mt-4">
|
||||
<h5 class="text-center no-print text-muted mb-3"><i class="bi bi-view-list"></i> <?= h(tr('معاينة الطباعة', 'Print Preview')) ?></h5>
|
||||
<?php
|
||||
$labelsPerPage = $tpl['cols'] * $tpl['rows'];
|
||||
$pages = array_chunk($labelsToPrint, $labelsPerPage);
|
||||
foreach ($pages as $pageIdx => $pageLabels):
|
||||
?>
|
||||
<div class="page bg-white">
|
||||
<?php foreach ($pageLabels as $label):
|
||||
?><div class="label-item">
|
||||
<div class="label-company"><?= h($companyName) ?></div>
|
||||
<div class="label-name"><?= h($label['name']) ?></div>
|
||||
<div class="label-barcode">
|
||||
<svg class="barcode"
|
||||
jsbarcode-format="code128"
|
||||
jsbarcode-value="<?= h($label['sku']) ?>"
|
||||
jsbarcode-displayvalue="false"
|
||||
jsbarcode-width="1"
|
||||
jsbarcode-height="12"
|
||||
jsbarcode-margin="0">
|
||||
</svg>
|
||||
</div>
|
||||
<div class="label-dates" dir="ltr" style="display: flex; justify-content: space-around; width: 100%;">
|
||||
<span>P:<?= h($label['prod_date']) ?></span><span>E:<?= h($label['exp_date']) ?></span>
|
||||
</div>
|
||||
<div class="label-price"><?= h(currency($label['price'])) ?></div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-4 mb-5 no-print">
|
||||
<button type="button" class="btn btn-success btn-lg px-5 py-3 shadow-lg rounded-pill" onclick="window.print()">
|
||||
<i class="bi bi-printer fs-4"></i> <?= h(tr('الطباعة الآن', 'Print Labels Now')) ?>
|
||||
</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
if (typeof JsBarcode !== 'undefined') {
|
||||
JsBarcode(".barcode").init();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -157,6 +157,7 @@ if (!empty($items)) {
|
||||
}
|
||||
|
||||
$isSinglePrint = isset($_GET['sku']) && count($skus) === 1;
|
||||
$companyName = current_lang() === 'ar' ? get_setting('company_name_ar', 'حلوى الريامي') : get_setting('company_name_en', 'Al Riyami Sweets');
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
@ -206,6 +207,7 @@ $isSinglePrint = isset($_GET['sku']) && count($skus) === 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.label-company { font-size: 9px; font-weight: bold; margin-bottom: 1px; text-transform: uppercase; }
|
||||
.label-name { font-size: 9px; font-weight: bold; line-height: 1.1; margin-bottom: 2px; max-height: 20px; overflow: hidden; }
|
||||
.label-price { font-size: 10px; font-weight: bold; margin-top: 1px; }
|
||||
.label-sku { font-size: 8px; color: #555; }
|
||||
@ -328,6 +330,7 @@ $isSinglePrint = isset($_GET['sku']) && count($skus) === 1;
|
||||
<div class="page bg-white">
|
||||
<?php foreach ($pageLabels as $label):
|
||||
?><div class="label-item">
|
||||
<div class="label-company"><?= h($companyName) ?></div>
|
||||
<div class="label-name"><?= h($label['name']) ?></div>
|
||||
<div class="label-barcode">
|
||||
<svg class="barcode"
|
||||
|
||||
@ -157,6 +157,7 @@ if (!empty($items)) {
|
||||
}
|
||||
|
||||
$isSinglePrint = isset($_GET['sku']) && count($skus) === 1;
|
||||
$companyName = current_lang() === 'ar' ? get_setting('company_name_ar', 'حلوى الريامي') : get_setting('company_name_en', 'Al Riyami Sweets');
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
@ -206,6 +207,7 @@ $isSinglePrint = isset($_GET['sku']) && count($skus) === 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.label-company { font-size: 9px; font-weight: bold; margin-bottom: 1px; text-transform: uppercase; }
|
||||
.label-name { font-size: 9px; font-weight: bold; line-height: 1.1; margin-bottom: 2px; max-height: 20px; overflow: hidden; }
|
||||
.label-price { font-size: 10px; font-weight: bold; margin-top: 1px; }
|
||||
.label-sku { font-size: 8px; color: #555; }
|
||||
@ -337,6 +339,7 @@ $isSinglePrint = isset($_GET['sku']) && count($skus) === 1;
|
||||
<div class="page bg-white">
|
||||
<?php foreach ($pageLabels as $label):
|
||||
?><div class="label-item">
|
||||
<div class="label-company"><?= h($companyName) ?></div>
|
||||
<div class="label-name"><?= h($label['name']) ?></div>
|
||||
<div class="label-barcode">
|
||||
<svg class="barcode"
|
||||
|
||||
@ -383,6 +383,9 @@ require __DIR__ . '/includes/header.php';
|
||||
<button type="button" onclick="printSingleLabel('<?= h(addslashes($row['sku'])) ?>')" class="btn btn-sm btn-outline-secondary rounded-circle shadow-sm ms-1" style="width: 34px; height: 34px; padding: 0;" data-bs-toggle="tooltip" title="<?= h(tr('طباعة ملصق', 'Print Label')) ?>">
|
||||
<i class="bi bi-printer"></i>
|
||||
</button>
|
||||
<button type="button" onclick="printLabelDates('<?= h(addslashes($row['sku'])) ?>')" class="btn btn-sm btn-outline-info rounded-circle shadow-sm ms-1" style="width: 34px; height: 34px; padding: 0;" data-bs-toggle="tooltip" title="<?= h(tr('طباعة ملصق مع التواريخ', 'Print Label with Dates')) ?>">
|
||||
<i class="bi bi-calendar-event"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger rounded-circle shadow-sm ms-1" style="width: 34px; height: 34px; padding: 0;" onclick="deleteItem('<?= h(addslashes($row['sku'])) ?>')" data-bs-toggle="tooltip" title="<?= h(tr('حذف', 'Delete')) ?>">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
@ -759,6 +762,10 @@ function printSingleLabel(sku) {
|
||||
}
|
||||
window.location.href = 'print_single_label.php?sku=' + encodeURIComponent(sku);
|
||||
}
|
||||
|
||||
function printLabelDates(sku) {
|
||||
window.location.href = 'print_label_dates.php?sku=' + encodeURIComponent(sku);
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php require __DIR__ . "/includes/footer.php"; ?>
|
||||
Loading…
x
Reference in New Issue
Block a user