changing labels print
This commit is contained in:
parent
be969df378
commit
07fac2272f
BIN
assets/pasted-20260213-034550-9dbf9cca.png
Normal file
BIN
assets/pasted-20260213-034550-9dbf9cca.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
29
check_libs.py
Normal file
29
check_libs.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import os
|
||||||
|
from cffi import FFI
|
||||||
|
|
||||||
|
ffi = FFI()
|
||||||
|
|
||||||
|
def _dlopen(*names):
|
||||||
|
for name in names:
|
||||||
|
try:
|
||||||
|
lib = ffi.dlopen(name)
|
||||||
|
print(f"Loaded {name}")
|
||||||
|
return lib
|
||||||
|
except OSError as e:
|
||||||
|
print(f"Failed to load {name}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
print("Checking gobject...")
|
||||||
|
_dlopen('libgobject-2.0-0', 'gobject-2.0-0', 'gobject-2.0', 'libgobject-2.0.so.0')
|
||||||
|
|
||||||
|
print("\nChecking pango...")
|
||||||
|
_dlopen('libpango-1.0-0', 'pango-1.0-0', 'pango-1.0', 'libpango-1.0.so.0')
|
||||||
|
|
||||||
|
print("\nChecking harfbuzz...")
|
||||||
|
_dlopen('libharfbuzz-0', 'harfbuzz', 'harfbuzz-0.0', 'libharfbuzz.so.0')
|
||||||
|
|
||||||
|
print("\nChecking fontconfig...")
|
||||||
|
_dlopen('libfontconfig-1', 'fontconfig-1', 'fontconfig', 'libfontconfig.so.1')
|
||||||
|
|
||||||
|
print("\nChecking pangoft2...")
|
||||||
|
_dlopen('libpangoft2-1.0-0', 'pangoft2-1.0-0', 'pangoft2-1.0', 'libpangoft2-1.0.so.0')
|
||||||
Binary file not shown.
Binary file not shown.
@ -5,9 +5,14 @@
|
|||||||
<div class="container-fluid mt-4 mb-5 no-print">
|
<div class="container-fluid mt-4 mb-5 no-print">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h2 class="h4 mb-0"><i class="bi bi-upc-scan me-2"></i>Barcode Label Printing</h2>
|
<h2 class="h4 mb-0"><i class="bi bi-upc-scan me-2"></i>Barcode Label Printing</h2>
|
||||||
<button id="printQueueBtn" class="btn btn-primary">
|
<div class="d-flex gap-2">
|
||||||
<i class="bi bi-printer me-2"></i>Print Label Queue
|
<button id="clearQueueBtn" class="btn btn-outline-danger">
|
||||||
</button>
|
<i class="bi bi-trash me-2"></i>Clear Queue
|
||||||
|
</button>
|
||||||
|
<button id="printQueueBtn" class="btn btn-primary">
|
||||||
|
<i class="bi bi-printer me-2"></i>Print Label Queue
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -132,24 +137,17 @@
|
|||||||
<!-- Live Preview -->
|
<!-- Live Preview -->
|
||||||
<div class="card shadow-sm border-0">
|
<div class="card shadow-sm border-0">
|
||||||
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center">
|
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center">
|
||||||
<h5 class="card-title mb-0">3. Live Preview (Single Label)</h5>
|
<h5 class="card-title mb-0">3. Live Preview (Queue Preview)</h5>
|
||||||
<button type="button" class="btn btn-sm btn-success" id="printPreviewBtn">
|
<button type="button" class="btn btn-sm btn-success" id="printPreviewBtn">
|
||||||
<i class="bi bi-printer me-1"></i>Print This Label
|
<i class="bi bi-printer me-1"></i>Print All in Queue
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body text-center bg-light p-5">
|
<div class="card-body text-center bg-light p-4">
|
||||||
<div id="previewContainer" class="d-inline-block bg-white shadow-sm p-3 border">
|
<div id="previewContainer" class="d-flex flex-wrap justify-content-center gap-3">
|
||||||
<div id="previewLabelContent">
|
<!-- Dynamic preview labels will be injected here -->
|
||||||
<div class="preview-name fw-bold small mb-1">Product Name</div>
|
|
||||||
<svg id="previewBarcode"></svg>
|
|
||||||
<div class="preview-footer d-flex justify-content-between mt-1 small">
|
|
||||||
<span class="preview-sku">SKU12345</span>
|
|
||||||
<span class="preview-price fw-bold">OMR 0.000</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 text-muted small">
|
<div class="mt-3 text-muted small">
|
||||||
Note: This is a preview of the layout. Actual print layout depends on settings above.
|
Note: This preview shows one of each product in your queue. Actual sheet layout will be generated on print.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -481,6 +479,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
printQueueBtn.addEventListener('click', handlePrintQueue);
|
printQueueBtn.addEventListener('click', handlePrintQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const clearQueueBtn = document.getElementById('clearQueueBtn');
|
||||||
|
if (clearQueueBtn) {
|
||||||
|
clearQueueBtn.addEventListener('click', function() {
|
||||||
|
if (confirm("Are you sure you want to clear the entire queue?")) {
|
||||||
|
queue.length = 0;
|
||||||
|
renderQueue();
|
||||||
|
updatePreview();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function handlePrintQueue() {
|
function handlePrintQueue() {
|
||||||
if (queue.length === 0) return;
|
if (queue.length === 0) return;
|
||||||
preparePrint();
|
preparePrint();
|
||||||
@ -491,7 +500,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
const printPreviewBtn = document.getElementById('printPreviewBtn');
|
const printPreviewBtn = document.getElementById('printPreviewBtn');
|
||||||
if (printPreviewBtn) {
|
if (printPreviewBtn) {
|
||||||
printPreviewBtn.addEventListener('click', printSingleFromPreview);
|
printPreviewBtn.addEventListener('click', handlePrintQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Product Search
|
// Product Search
|
||||||
@ -514,38 +523,90 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
// --- PREVIEW LOGIC ---
|
// --- PREVIEW LOGIC ---
|
||||||
function updatePreview() {
|
function updatePreview() {
|
||||||
let product = null;
|
const container = document.getElementById('previewContainer');
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
container.innerHTML = '';
|
||||||
|
|
||||||
|
// Items to show: either everything in the queue, or the last added if queue is empty
|
||||||
|
let itemsToShow = [];
|
||||||
if (queue.length > 0) {
|
if (queue.length > 0) {
|
||||||
product = queue[queue.length - 1];
|
itemsToShow = [...queue];
|
||||||
} else if (lastAddedProduct) {
|
} else if (lastAddedProduct) {
|
||||||
product = lastAddedProduct;
|
itemsToShow = [lastAddedProduct];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!product) return;
|
|
||||||
|
|
||||||
const previewName = document.querySelector('.preview-name');
|
|
||||||
const previewSku = document.querySelector('.preview-sku');
|
|
||||||
const previewPrice = document.querySelector('.preview-price');
|
|
||||||
|
|
||||||
if (previewName) previewName.innerHTML = (product.nameAr ? `<div class='text-end'>${product.nameAr}</div>` : '') + `<div>${product.name}</div>`;
|
|
||||||
if (previewSku) previewSku.innerText = product.sku;
|
|
||||||
if (previewPrice) previewPrice.innerText = 'OMR ' + parseFloat(product.price).toFixed(3);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (typeof JsBarcode !== 'undefined') {
|
|
||||||
JsBarcode("#previewBarcode", product.sku, {
|
|
||||||
format: "CODE128", width: 2, height: 40, displayValue: false, margin: 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch(e) {}
|
|
||||||
|
|
||||||
|
if (itemsToShow.length === 0) {
|
||||||
|
container.innerHTML = '<div class="py-4 text-muted">No items selected for preview</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const labelType = document.getElementById('labelType').value;
|
||||||
const showName = document.getElementById('showName').checked;
|
const showName = document.getElementById('showName').checked;
|
||||||
const showPrice = document.getElementById('showPrice').checked;
|
const showPrice = document.getElementById('showPrice').checked;
|
||||||
const showSKU = document.getElementById('showSKU').checked;
|
const showSKU = document.getElementById('showSKU').checked;
|
||||||
|
|
||||||
if (previewName) previewName.style.display = showName ? '' : 'none';
|
itemsToShow.forEach((p, idx) => {
|
||||||
if (previewPrice) previewPrice.style.display = showPrice ? '' : 'none';
|
const previewItem = document.createElement('div');
|
||||||
if (previewSku) previewSku.style.display = showSKU ? '' : 'none';
|
previewItem.className = 'bg-white shadow-sm border p-2 d-flex flex-column align-items-center justify-content-center position-relative';
|
||||||
|
|
||||||
|
// Apply approximate styles based on labelType for the preview
|
||||||
|
let pWidth = "180px";
|
||||||
|
let pHeight = "auto";
|
||||||
|
let minHeight = "100px";
|
||||||
|
|
||||||
|
if (labelType === 'l7651') { pWidth = "150px"; minHeight = "80px"; }
|
||||||
|
else if (labelType === 'l7656') { pWidth = "180px"; minHeight = "50px"; }
|
||||||
|
else if (labelType === 'a4-40') { pWidth = "160px"; minHeight = "90px"; }
|
||||||
|
|
||||||
|
previewItem.style.width = pWidth;
|
||||||
|
previewItem.style.minHeight = minHeight;
|
||||||
|
|
||||||
|
let content = '';
|
||||||
|
if (p.qty > 1) {
|
||||||
|
content += `<span class="badge bg-secondary position-absolute top-0 end-0 m-1" title="Quantity to print">${p.qty}x</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelType === 'l7656') {
|
||||||
|
content = `<div class="d-flex align-items-center justify-content-between w-100 gap-2">`;
|
||||||
|
if (showName) content += `<div class="small fw-bold text-start" style="font-size: 0.7rem; max-width: 60px;">${p.nameAr ? p.nameAr + " " : ""}${p.name}</div>`;
|
||||||
|
content += `<svg class="preview-barcode-item"></svg>`;
|
||||||
|
if (showPrice) content += `<div class="small fw-bold" style="font-size: 0.7rem;">${parseFloat(p.price).toFixed(3)}</div>`;
|
||||||
|
content += `</div>`;
|
||||||
|
} else {
|
||||||
|
if (showName) {
|
||||||
|
content += `<div class="fw-bold small mb-1 w-100 text-center text-truncate" title="${p.name}">`;
|
||||||
|
if (p.nameAr) content += `<div class="text-muted" style="font-size: 0.7rem">${p.nameAr}</div>`;
|
||||||
|
content += `${p.name}</div>`;
|
||||||
|
}
|
||||||
|
content += `<svg class="preview-barcode-item"></svg>`;
|
||||||
|
if (showSKU || showPrice) {
|
||||||
|
content += `<div class="d-flex justify-content-between w-100 mt-1" style="font-size: 0.7rem;">`;
|
||||||
|
if (showSKU) content += `<span class="text-muted">${p.sku}</span>`;
|
||||||
|
if (showPrice) content += `<span class="fw-bold text-success">OMR ${parseFloat(p.price).toFixed(3)}</span>`;
|
||||||
|
content += `</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previewItem.innerHTML = content;
|
||||||
|
container.appendChild(previewItem);
|
||||||
|
|
||||||
|
// Render barcode
|
||||||
|
const svgEl = previewItem.querySelector('.preview-barcode-item');
|
||||||
|
if (svgEl && typeof JsBarcode !== 'undefined') {
|
||||||
|
let bWidth = 1.2;
|
||||||
|
let bHeight = 30;
|
||||||
|
if (labelType === 'l7651') { bWidth = 0.9; bHeight = 20; }
|
||||||
|
else if (labelType === 'l7656') { bWidth = 0.8; bHeight = 15; }
|
||||||
|
else if (labelType === 'price-tag') { bWidth = 0.8; bHeight = 15; }
|
||||||
|
|
||||||
|
try {
|
||||||
|
JsBarcode(svgEl, p.sku, {
|
||||||
|
format: "CODE128", width: bWidth, height: bHeight, displayValue: false, margin: 0
|
||||||
|
});
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- DIRECT PRINT ---
|
// --- DIRECT PRINT ---
|
||||||
@ -560,16 +621,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
performDirectPrint(product);
|
performDirectPrint(product);
|
||||||
}
|
}
|
||||||
|
|
||||||
function printSingleFromPreview() {
|
|
||||||
let product = null;
|
|
||||||
if (queue.length > 0) {
|
|
||||||
product = queue[queue.length - 1];
|
|
||||||
} else if (lastAddedProduct) {
|
|
||||||
product = lastAddedProduct;
|
|
||||||
}
|
|
||||||
if (product) performDirectPrint(product);
|
|
||||||
}
|
|
||||||
|
|
||||||
function performDirectPrint(product) {
|
function performDirectPrint(product) {
|
||||||
document.body.classList.add('direct-print-mode');
|
document.body.classList.add('direct-print-mode');
|
||||||
printArea.innerHTML = '';
|
printArea.innerHTML = '';
|
||||||
@ -718,7 +769,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- SETUP LISTENERS ---
|
// --- SETUP LISTENERS ---
|
||||||
document.getElementById('labelType').addEventListener('change', () => preparePrint());
|
document.getElementById('labelType').addEventListener('change', () => { updatePreview(); preparePrint(); });
|
||||||
document.getElementById('showName').addEventListener('change', () => { updatePreview(); preparePrint(); });
|
document.getElementById('showName').addEventListener('change', () => { updatePreview(); preparePrint(); });
|
||||||
document.getElementById('showPrice').addEventListener('change', () => { updatePreview(); preparePrint(); });
|
document.getElementById('showPrice').addEventListener('change', () => { updatePreview(); preparePrint(); });
|
||||||
document.getElementById('showSKU').addEventListener('change', () => { updatePreview(); preparePrint(); });
|
document.getElementById('showSKU').addEventListener('change', () => { updatePreview(); preparePrint(); });
|
||||||
|
|||||||
@ -172,4 +172,5 @@ urlpatterns = [
|
|||||||
# Database Backup/Restore
|
# Database Backup/Restore
|
||||||
path('settings/backup/', views.backup_database, name='backup_database'),
|
path('settings/backup/', views.backup_database, name='backup_database'),
|
||||||
path('settings/restore/', views.restore_database, name='restore_database'),
|
path('settings/restore/', views.restore_database, name='restore_database'),
|
||||||
|
path('api/test-pdf/', views.test_pdf_view, name='test_pdf_view'),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -43,6 +43,16 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
# --- Basic Views ---
|
# --- Basic Views ---
|
||||||
|
|
||||||
|
def test_pdf_view(request):
|
||||||
|
from weasyprint import HTML
|
||||||
|
html_string = "<h1>Test PDF</h1>"
|
||||||
|
pdf = HTML(string=html_string).write_pdf()
|
||||||
|
return HttpResponse(pdf, content_type='application/pdf')
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def dashboard(request):
|
||||||
|
return redirect('core:index')
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def index(request):
|
def index(request):
|
||||||
settings = SystemSetting.objects.first()
|
settings = SystemSetting.objects.first()
|
||||||
|
|||||||
33
reproduce_error.py
Normal file
33
reproduce_error.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
import os
|
||||||
|
import django
|
||||||
|
from django.conf import settings as django_settings
|
||||||
|
from django.template.loader import render_to_string
|
||||||
|
from django.test import RequestFactory
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
from core.views import generate_pdf_file
|
||||||
|
from core.models import Sale
|
||||||
|
|
||||||
|
def test_pdf():
|
||||||
|
try:
|
||||||
|
sale = Sale.objects.first()
|
||||||
|
if not sale:
|
||||||
|
print("No sales found")
|
||||||
|
return
|
||||||
|
|
||||||
|
request = RequestFactory().get('/')
|
||||||
|
context = {'sale': sale} # Simplified context
|
||||||
|
|
||||||
|
print("Testing PDF generation...")
|
||||||
|
pdf = generate_pdf_file('pdf/invoice_pdf.html', context, request)
|
||||||
|
print(f"PDF generated successfully, size: {len(pdf)}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Caught error: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_pdf()
|
||||||
23
test_weasyprint.py
Normal file
23
test_weasyprint.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import django
|
||||||
|
from django.conf import settings as django_settings
|
||||||
|
from django.template.loader import render_to_string
|
||||||
|
|
||||||
|
# Setup Django
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
def test_pdf():
|
||||||
|
from weasyprint import HTML
|
||||||
|
print("Imported weasyprint")
|
||||||
|
html_string = "<h1>Test</h1>"
|
||||||
|
try:
|
||||||
|
pdf = HTML(string=html_string).write_pdf()
|
||||||
|
print(f"Success! PDF size: {len(pdf)}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_pdf()
|
||||||
Loading…
x
Reference in New Issue
Block a user