diff --git a/assets/pasted-20260213-034550-9dbf9cca.png b/assets/pasted-20260213-034550-9dbf9cca.png new file mode 100644 index 0000000..7c1c09b Binary files /dev/null and b/assets/pasted-20260213-034550-9dbf9cca.png differ diff --git a/check_libs.py b/check_libs.py new file mode 100644 index 0000000..c537d23 --- /dev/null +++ b/check_libs.py @@ -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') diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 2ec899d..ef3970e 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 553eb16..68a3e28 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/templates/core/barcode_labels.html b/core/templates/core/barcode_labels.html index 15ad3dd..0dd3907 100644 --- a/core/templates/core/barcode_labels.html +++ b/core/templates/core/barcode_labels.html @@ -5,9 +5,14 @@

Barcode Label Printing

- +
+ + +
@@ -132,24 +137,17 @@
-
3. Live Preview (Single Label)
+
3. Live Preview (Queue Preview)
-
-
-
-
Product Name
- - -
+
+
+
- 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.
@@ -481,6 +479,17 @@ document.addEventListener('DOMContentLoaded', function() { 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() { if (queue.length === 0) return; preparePrint(); @@ -491,7 +500,7 @@ document.addEventListener('DOMContentLoaded', function() { const printPreviewBtn = document.getElementById('printPreviewBtn'); if (printPreviewBtn) { - printPreviewBtn.addEventListener('click', printSingleFromPreview); + printPreviewBtn.addEventListener('click', handlePrintQueue); } // Product Search @@ -514,38 +523,90 @@ document.addEventListener('DOMContentLoaded', function() { // --- PREVIEW LOGIC --- 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) { - product = queue[queue.length - 1]; + itemsToShow = [...queue]; } 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 ? `
${product.nameAr}
` : '') + `
${product.name}
`; - 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 = '
No items selected for preview
'; + return; + } + + const labelType = document.getElementById('labelType').value; const showName = document.getElementById('showName').checked; const showPrice = document.getElementById('showPrice').checked; const showSKU = document.getElementById('showSKU').checked; - - if (previewName) previewName.style.display = showName ? '' : 'none'; - if (previewPrice) previewPrice.style.display = showPrice ? '' : 'none'; - if (previewSku) previewSku.style.display = showSKU ? '' : 'none'; + + itemsToShow.forEach((p, idx) => { + const previewItem = document.createElement('div'); + 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 += `${p.qty}x`; + } + + if (labelType === 'l7656') { + content = `
`; + if (showName) content += `
${p.nameAr ? p.nameAr + " " : ""}${p.name}
`; + content += ``; + if (showPrice) content += `
${parseFloat(p.price).toFixed(3)}
`; + content += `
`; + } else { + if (showName) { + content += `
`; + if (p.nameAr) content += `
${p.nameAr}
`; + content += `${p.name}
`; + } + content += ``; + if (showSKU || showPrice) { + content += `
`; + if (showSKU) content += `${p.sku}`; + if (showPrice) content += `OMR ${parseFloat(p.price).toFixed(3)}`; + content += `
`; + } + } + + 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 --- @@ -560,16 +621,6 @@ document.addEventListener('DOMContentLoaded', function() { 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) { document.body.classList.add('direct-print-mode'); printArea.innerHTML = ''; @@ -718,7 +769,7 @@ document.addEventListener('DOMContentLoaded', function() { } // --- SETUP LISTENERS --- - document.getElementById('labelType').addEventListener('change', () => preparePrint()); + document.getElementById('labelType').addEventListener('change', () => { updatePreview(); preparePrint(); }); document.getElementById('showName').addEventListener('change', () => { updatePreview(); preparePrint(); }); document.getElementById('showPrice').addEventListener('change', () => { updatePreview(); preparePrint(); }); document.getElementById('showSKU').addEventListener('change', () => { updatePreview(); preparePrint(); }); diff --git a/core/urls.py b/core/urls.py index 55e785f..601d69c 100644 --- a/core/urls.py +++ b/core/urls.py @@ -172,4 +172,5 @@ urlpatterns = [ # Database Backup/Restore path('settings/backup/', views.backup_database, name='backup_database'), path('settings/restore/', views.restore_database, name='restore_database'), + path('api/test-pdf/', views.test_pdf_view, name='test_pdf_view'), ] diff --git a/core/views.py b/core/views.py index e74f492..078e5b4 100644 --- a/core/views.py +++ b/core/views.py @@ -43,6 +43,16 @@ logger = logging.getLogger(__name__) # --- Basic Views --- +def test_pdf_view(request): + from weasyprint import HTML + html_string = "

Test PDF

" + 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 def index(request): settings = SystemSetting.objects.first() diff --git a/reproduce_error.py b/reproduce_error.py new file mode 100644 index 0000000..2fc746b --- /dev/null +++ b/reproduce_error.py @@ -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() diff --git a/test_weasyprint.py b/test_weasyprint.py new file mode 100644 index 0000000..85f49a4 --- /dev/null +++ b/test_weasyprint.py @@ -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 = "

Test

" + 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()