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="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>
|
||||
<button id="printQueueBtn" class="btn btn-primary">
|
||||
<i class="bi bi-printer me-2"></i>Print Label Queue
|
||||
</button>
|
||||
<div class="d-flex gap-2">
|
||||
<button id="clearQueueBtn" class="btn btn-outline-danger">
|
||||
<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 class="row">
|
||||
@ -132,24 +137,17 @@
|
||||
<!-- Live Preview -->
|
||||
<div class="card shadow-sm border-0">
|
||||
<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">
|
||||
<i class="bi bi-printer me-1"></i>Print This Label
|
||||
<i class="bi bi-printer me-1"></i>Print All in Queue
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body text-center bg-light p-5">
|
||||
<div id="previewContainer" class="d-inline-block bg-white shadow-sm p-3 border">
|
||||
<div id="previewLabelContent">
|
||||
<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 class="card-body text-center bg-light p-4">
|
||||
<div id="previewContainer" class="d-flex flex-wrap justify-content-center gap-3">
|
||||
<!-- Dynamic preview labels will be injected here -->
|
||||
</div>
|
||||
<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>
|
||||
@ -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 ? `<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 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 += `<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 ---
|
||||
@ -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(); });
|
||||
|
||||
@ -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'),
|
||||
]
|
||||
|
||||
@ -43,6 +43,16 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
# --- 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
|
||||
def index(request):
|
||||
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