u
This commit is contained in:
@@ -413,16 +413,16 @@ export function generateManifestPdf({
|
||||
|
||||
// Delivery columns (Wareneingang)
|
||||
const colDeliv = {
|
||||
check: 53, checkW: 18,
|
||||
pos: 71, posW: 18,
|
||||
thumb: 89, thumbW: 30,
|
||||
suppSku: 119, suppSkuW: 52,
|
||||
ownSku: 171, ownSkuW: 92,
|
||||
ean: 263, eanW: 78,
|
||||
name: 341, nameW: 85,
|
||||
deliv: 426, delivW: 38,
|
||||
stock: 464, stockW: 38,
|
||||
added: 502, addedW: 40,
|
||||
pos: 45, posW: 20,
|
||||
thumb: 67, thumbW: 30,
|
||||
suppSku: 99, suppSkuW: 52,
|
||||
ownSku: 153, ownSkuW: 92,
|
||||
ean: 247, eanW: 78,
|
||||
name: 327, nameW: 81,
|
||||
check: 410, checkW: 18,
|
||||
deliv: 428, delivW: 40,
|
||||
added: 468, addedW: 42,
|
||||
stock: 510, stockW: 38,
|
||||
};
|
||||
|
||||
const drawTableHeader = (atY) => {
|
||||
@@ -435,7 +435,6 @@ export function generateManifestPdf({
|
||||
.fillColor('#ffffff');
|
||||
|
||||
if (isDelivery) {
|
||||
|
||||
doc.text('Pos', colDeliv.pos, atY + 6, { width: colDeliv.posW, align: 'center' });
|
||||
doc.text('Bild', colDeliv.thumb, atY + 6, { width: colDeliv.thumbW, align: 'center' });
|
||||
doc.text('Lief.-SKU', colDeliv.suppSku, atY + 6, { width: colDeliv.suppSkuW });
|
||||
@@ -443,8 +442,8 @@ export function generateManifestPdf({
|
||||
doc.text('EAN', colDeliv.ean, atY + 6, { width: colDeliv.eanW });
|
||||
doc.text('Bezeichnung', colDeliv.name, atY + 6, { width: colDeliv.nameW });
|
||||
doc.text('Geliefert', colDeliv.deliv, atY + 6, { width: colDeliv.delivW, align: 'right' });
|
||||
doc.text('Bestand', colDeliv.stock, atY + 6, { width: colDeliv.stockW, align: 'right' });
|
||||
doc.text('Gebucht', colDeliv.added, atY + 6, { width: colDeliv.addedW, align: 'right' });
|
||||
doc.text('Bestand', colDeliv.stock, atY + 6, { width: colDeliv.stockW, align: 'right' });
|
||||
} else if (showPrices) {
|
||||
doc.fontSize(8);
|
||||
doc.text('Pos', colXPrices.pos + 3, atY + 6, { width: colWidthPrices.pos });
|
||||
@@ -503,7 +502,118 @@ export function generateManifestPdf({
|
||||
|
||||
const nameWidth = showPrices ? colWidthPrices.name : colWidthNoPrices.name;
|
||||
const puSuffix = line.pu && line.pu > 1 ? ` (VPE ${line.pu})` : '';
|
||||
const nameText = (line.name || 'Position') + puSuffix;
|
||||
const ownName = (line.ownArticleName || line.articleName || '').trim();
|
||||
const baseName = (isDelivery && line.ownSku && ownName)
|
||||
? ownName
|
||||
: (line.name || 'Position');
|
||||
const nameText = baseName + puSuffix;
|
||||
|
||||
if (isDelivery) {
|
||||
const rowHeight = 38;
|
||||
if (y + rowHeight > 730) {
|
||||
doc.addPage();
|
||||
y = drawTableHeader(45);
|
||||
}
|
||||
|
||||
if (index % 2 === 1) {
|
||||
doc.rect(45, y - 2, 505, rowHeight)
|
||||
.fillColor(lightBg)
|
||||
.fill();
|
||||
}
|
||||
|
||||
const centerY = y + 12;
|
||||
|
||||
// 1. Pos
|
||||
doc.font('Helvetica')
|
||||
.fontSize(8.5)
|
||||
.fillColor(textColor)
|
||||
.text(String(index + 1), colDeliv.pos, centerY, { width: colDeliv.posW, align: 'center' });
|
||||
|
||||
// 2. Thumbpic
|
||||
if (line.thumbPng) {
|
||||
try {
|
||||
doc.image(line.thumbPng, colDeliv.thumb + 2, y + 4, {
|
||||
fit: [26, 26],
|
||||
align: 'center',
|
||||
valign: 'center',
|
||||
});
|
||||
} catch (_) {
|
||||
doc.roundedRect(colDeliv.thumb + 2, y + 4, 26, 26, 2)
|
||||
.fillColor('#f1f5f9').fill()
|
||||
.strokeColor('#cbd5e1').lineWidth(0.5).stroke();
|
||||
}
|
||||
} else {
|
||||
doc.roundedRect(colDeliv.thumb + 2, y + 4, 26, 26, 2)
|
||||
.fillColor('#f1f5f9').fill()
|
||||
.strokeColor('#cbd5e1').lineWidth(0.5).stroke();
|
||||
doc.font('Helvetica').fontSize(6).fillColor(mutedColor).text('Kein Bild', colDeliv.thumb + 2, y + 14, { width: 26, align: 'center' });
|
||||
}
|
||||
|
||||
// 3. Supplier SKU
|
||||
doc.font('Helvetica').fontSize(7.5).fillColor(textColor)
|
||||
.text(line.supplierSku || '–', colDeliv.suppSku, y + 12, { width: colDeliv.suppSkuW, ellipsis: true });
|
||||
|
||||
// 4. Eigene SKU as text + Code128 Barcode
|
||||
const ownSkuText = line.ownSku || '–';
|
||||
doc.font('Helvetica-Bold').fontSize(7).fillColor(primaryColor)
|
||||
.text(ownSkuText, colDeliv.ownSku, y + 2, { width: colDeliv.ownSkuW, ellipsis: true });
|
||||
if (line.ownSkuBarcode) {
|
||||
try {
|
||||
doc.image(line.ownSkuBarcode, colDeliv.ownSku, y + 12, { width: 88, height: 20 });
|
||||
} catch (_) { }
|
||||
}
|
||||
|
||||
// 5. EAN as barcode
|
||||
if (line.ean) {
|
||||
doc.font('Helvetica').fontSize(6.5).fillColor(mutedColor)
|
||||
.text(line.ean, colDeliv.ean, y + 2, { width: colDeliv.eanW, ellipsis: true });
|
||||
if (line.eanBarcode) {
|
||||
try {
|
||||
doc.image(line.eanBarcode, colDeliv.ean, y + 12, { width: 76, height: 20 });
|
||||
} catch (_) { }
|
||||
}
|
||||
} else {
|
||||
doc.font('Helvetica').fontSize(8).fillColor(mutedColor)
|
||||
.text('–', colDeliv.ean, y + 12, { width: colDeliv.eanW, align: 'center' });
|
||||
}
|
||||
|
||||
// 6. Name (own article name if own SKU is connected)
|
||||
doc.font('Helvetica').fontSize(7.5).fillColor(textColor)
|
||||
.text(nameText, colDeliv.name, y + 6, { width: colDeliv.nameW });
|
||||
|
||||
// 7. Checkbox outline (to cross with pencil) - left of geliefert
|
||||
doc.rect(colDeliv.check + 3, centerY - 1, 12, 12)
|
||||
.strokeColor('#64748b')
|
||||
.lineWidth(0.8)
|
||||
.stroke();
|
||||
|
||||
// 8. Menge geliefert
|
||||
doc.font('Helvetica-Bold').fontSize(8).fillColor(textColor)
|
||||
.text(formatQuantity(amount) + ' Stk', colDeliv.deliv, y + 12, { width: colDeliv.delivW, align: 'right' });
|
||||
|
||||
// 9. Menge added / gebucht (swapped before bestand)
|
||||
const hasBooked = line.trackStock && line.addedQuantity != null && line.addedQuantity > 0;
|
||||
const bookedText = line.trackStock
|
||||
? (line.addedQuantity != null && line.addedQuantity > 0 ? `+${formatQuantity(line.addedQuantity)} Stk` : (line.addedQuantity === 0 ? '0 Stk' : '–'))
|
||||
: '–';
|
||||
doc.font('Helvetica-Bold').fontSize(8).fillColor(hasBooked ? '#16a34a' : mutedColor)
|
||||
.text(bookedText, colDeliv.added, y + 12, { width: colDeliv.addedW, align: 'right' });
|
||||
|
||||
// 10. Menge already in warehouse (bestand)
|
||||
const stockText = line.trackStock ? (formatQuantity(line.currentStock ?? 0) + ' Stk') : '–';
|
||||
doc.font('Helvetica').fontSize(7.5).fillColor(line.trackStock ? textColor : mutedColor)
|
||||
.text(stockText, colDeliv.stock, y + 12, { width: colDeliv.stockW, align: 'right' });
|
||||
|
||||
// Row separator
|
||||
doc.moveTo(45, y + rowHeight - 2)
|
||||
.lineTo(550, y + rowHeight - 2)
|
||||
.strokeColor(lightBorder)
|
||||
.lineWidth(0.5)
|
||||
.stroke();
|
||||
|
||||
y += rowHeight;
|
||||
return;
|
||||
}
|
||||
|
||||
// Measure actual rendered text heights to prevent overlaps
|
||||
doc.font('Helvetica').fontSize(8.5);
|
||||
@@ -542,113 +652,6 @@ export function generateManifestPdf({
|
||||
|
||||
const textY = y + 1;
|
||||
|
||||
if (isDelivery) {
|
||||
const rowHeight = 38;
|
||||
if (y + rowHeight > 730) {
|
||||
doc.addPage();
|
||||
y = drawTableHeader(45);
|
||||
}
|
||||
|
||||
if (index % 2 === 1) {
|
||||
doc.rect(45, y - 2, 505, rowHeight)
|
||||
.fillColor(lightBg)
|
||||
.fill();
|
||||
}
|
||||
|
||||
const centerY = y + 12;
|
||||
|
||||
// 1. Checkbox outline (to cross with pencil)
|
||||
doc.rect(colDeliv.check + 3, centerY - 1, 12, 12)
|
||||
.strokeColor('#64748b')
|
||||
.lineWidth(0.8)
|
||||
.stroke();
|
||||
|
||||
// 2. Pos
|
||||
doc.font('Helvetica')
|
||||
.fontSize(8.5)
|
||||
.fillColor(textColor)
|
||||
.text(String(index + 1), colDeliv.pos, centerY, { width: colDeliv.posW, align: 'center' });
|
||||
|
||||
// 3. Thumbpic
|
||||
if (line.thumbPng) {
|
||||
try {
|
||||
doc.image(line.thumbPng, colDeliv.thumb + 2, y + 4, {
|
||||
fit: [26, 26],
|
||||
align: 'center',
|
||||
valign: 'center',
|
||||
});
|
||||
} catch (_) {
|
||||
doc.roundedRect(colDeliv.thumb + 2, y + 4, 26, 26, 2)
|
||||
.fillColor('#f1f5f9').fill()
|
||||
.strokeColor('#cbd5e1').lineWidth(0.5).stroke();
|
||||
}
|
||||
} else {
|
||||
doc.roundedRect(colDeliv.thumb + 3, y + 4, 26, 26, 2)
|
||||
.fillColor('#f1f5f9').fill()
|
||||
.strokeColor('#cbd5e1').lineWidth(0.5).stroke();
|
||||
doc.font('Helvetica').fontSize(6).fillColor(mutedColor).text('Kein Bild', colDeliv.thumb + 2, y + 14, { width: 26, align: 'center' });
|
||||
}
|
||||
|
||||
// 4. Supplier SKU
|
||||
doc.font('Helvetica').fontSize(7.5).fillColor(textColor)
|
||||
.text(line.supplierSku || '–', colDeliv.suppSku, y + 12, { width: colDeliv.suppSkuW, ellipsis: true });
|
||||
|
||||
// 5. Eigene SKU as text + Code128 Barcode
|
||||
const ownSkuText = line.ownSku || line.sku || '–';
|
||||
doc.font('Helvetica-Bold').fontSize(7).fillColor(primaryColor)
|
||||
.text(ownSkuText, colDeliv.ownSku, y + 2, { width: colDeliv.ownSkuW, ellipsis: true });
|
||||
if (line.ownSkuBarcode) {
|
||||
try {
|
||||
doc.image(line.ownSkuBarcode, colDeliv.ownSku, y + 12, { width: 88, height: 20 });
|
||||
} catch (_) { }
|
||||
}
|
||||
|
||||
// 6. EAN as barcode
|
||||
if (line.ean) {
|
||||
doc.font('Helvetica').fontSize(6.5).fillColor(mutedColor)
|
||||
.text(line.ean, colDeliv.ean, y + 2, { width: colDeliv.eanW, ellipsis: true });
|
||||
if (line.eanBarcode) {
|
||||
try {
|
||||
doc.image(line.eanBarcode, colDeliv.ean, y + 12, { width: 76, height: 20 });
|
||||
} catch (_) { }
|
||||
}
|
||||
} else {
|
||||
doc.font('Helvetica').fontSize(8).fillColor(mutedColor)
|
||||
.text('–', colDeliv.ean, y + 12, { width: colDeliv.eanW, align: 'center' });
|
||||
}
|
||||
|
||||
// 7. Name
|
||||
doc.font('Helvetica').fontSize(7.5).fillColor(textColor)
|
||||
.text(nameText, colDeliv.name, y + 6, { width: colDeliv.nameW });
|
||||
|
||||
// 8. Menge geliefert
|
||||
doc.font('Helvetica-Bold').fontSize(8).fillColor(textColor)
|
||||
.text(formatQuantity(amount) + ' Stk', colDeliv.deliv, y + 12, { width: colDeliv.delivW, align: 'right' });
|
||||
|
||||
// 9. Menge already in warehouse
|
||||
const stockText = line.trackStock ? (formatQuantity(line.currentStock ?? 0) + ' Stk') : '–';
|
||||
doc.font('Helvetica').fontSize(7.5).fillColor(line.trackStock ? textColor : mutedColor)
|
||||
.text(stockText, colDeliv.stock, y + 12, { width: colDeliv.stockW, align: 'right' });
|
||||
|
||||
// 10. Menge added / gebucht
|
||||
const hasBooked = line.trackStock && line.addedQuantity != null && line.addedQuantity > 0;
|
||||
const bookedText = line.trackStock
|
||||
? (line.addedQuantity != null && line.addedQuantity > 0 ? `+${formatQuantity(line.addedQuantity)} Stk` : (line.addedQuantity === 0 ? '0 Stk' : '–'))
|
||||
: '–';
|
||||
doc.font('Helvetica-Bold').fontSize(8).fillColor(hasBooked ? '#16a34a' : mutedColor)
|
||||
.text(bookedText, colDeliv.added, y + 12, { width: colDeliv.addedW, align: 'right' });
|
||||
|
||||
// Row separator
|
||||
doc.moveTo(45, y + rowHeight - 2)
|
||||
.lineTo(550, y + rowHeight - 2)
|
||||
.strokeColor(lightBorder)
|
||||
.lineWidth(0.5)
|
||||
.stroke();
|
||||
|
||||
y += rowHeight;
|
||||
return;
|
||||
}
|
||||
|
||||
if (showPrices) {
|
||||
doc.font('Helvetica')
|
||||
.fontSize(8.5)
|
||||
@@ -981,7 +984,8 @@ export async function createAndAttachManifestPdf(googleAuthId, companyId, manife
|
||||
manifest.lines = await Promise.all(
|
||||
manifest.lines.map(async (line) => {
|
||||
const rawSku = line.sku ? String(line.sku).trim() : '';
|
||||
let ownSku = rawSku;
|
||||
let ownSku = '';
|
||||
let ownArticleName = '';
|
||||
let supplierSku = '';
|
||||
let ean = '';
|
||||
let trackStock = false;
|
||||
@@ -992,23 +996,23 @@ export async function createAndAttachManifestPdf(googleAuthId, companyId, manife
|
||||
|
||||
if (rawSku) {
|
||||
const findSql = isSqlite
|
||||
? `SELECT a.id, a.sku, a.track_stock, at.name,
|
||||
? `SELECT a.id, a.sku, a.track_stock,
|
||||
(SELECT at.name FROM articletext at WHERE at.article_id = a.id ORDER BY CASE WHEN at.language_id = (SELECT default_language_id FROM company WHERE id = @companyId) THEN 0 ELSE 1 END, at.id ASC LIMIT 1) AS article_name,
|
||||
(SELECT asup.sku FROM articlesupplier asup WHERE asup.article_id = a.id AND (asup.entity_id = @partnerId OR @partnerId IS NULL) LIMIT 1) AS supplier_sku,
|
||||
(SELECT ae.ean FROM articleean ae WHERE ae.article_id = a.id ORDER BY ae.id ASC LIMIT 1) AS ean,
|
||||
(SELECT p.hash FROM articlepic ap INNER JOIN pic p ON p.id = ap.pic_id WHERE ap.article_id = a.id ORDER BY ap.sort ASC LIMIT 1) AS pic_hash,
|
||||
(SELECT p.smallthumbbinary FROM articlepic ap INNER JOIN pic p ON p.id = ap.pic_id WHERE ap.article_id = a.id ORDER BY ap.sort ASC LIMIT 1) AS smallthumbbinary
|
||||
FROM article a
|
||||
LEFT JOIN articletext at ON at.article_id = a.id
|
||||
WHERE a.company_id = @companyId
|
||||
AND (a.sku = @sku OR EXISTS (SELECT 1 FROM articlesupplier asup WHERE asup.article_id = a.id AND asup.sku = @sku))
|
||||
LIMIT 1`
|
||||
: `SELECT TOP 1 a.id, a.sku, a.track_stock, at.name,
|
||||
: `SELECT TOP 1 a.id, a.sku, a.track_stock,
|
||||
(SELECT TOP 1 at.name FROM articletext at WHERE at.article_id = a.id ORDER BY CASE WHEN at.language_id = (SELECT default_language_id FROM company WHERE id = @companyId) THEN 0 ELSE 1 END, at.id ASC) AS article_name,
|
||||
(SELECT TOP 1 asup.sku FROM articlesupplier asup WHERE asup.article_id = a.id AND (asup.entity_id = @partnerId OR @partnerId IS NULL)) AS supplier_sku,
|
||||
(SELECT TOP 1 ae.ean FROM articleean ae WHERE ae.article_id = a.id ORDER BY ae.id ASC) AS ean,
|
||||
(SELECT TOP 1 p.hash FROM articlepic ap INNER JOIN pic p ON p.id = ap.pic_id WHERE ap.article_id = a.id ORDER BY ap.sort ASC) AS pic_hash,
|
||||
(SELECT TOP 1 p.smallthumbbinary FROM articlepic ap INNER JOIN pic p ON p.id = ap.pic_id WHERE ap.article_id = a.id ORDER BY ap.sort ASC) AS smallthumbbinary
|
||||
FROM article a
|
||||
LEFT JOIN articletext at ON at.article_id = a.id
|
||||
WHERE a.company_id = @companyId
|
||||
AND (a.sku = @sku OR EXISTS (SELECT 1 FROM articlesupplier asup WHERE asup.article_id = a.id AND asup.sku = @sku))`;
|
||||
|
||||
@@ -1017,6 +1021,7 @@ export async function createAndAttachManifestPdf(googleAuthId, companyId, manife
|
||||
if (art) {
|
||||
articleId = art.id;
|
||||
ownSku = art.sku || rawSku;
|
||||
ownArticleName = (art.article_name || art.name || '').trim();
|
||||
supplierSku = art.supplier_sku || (rawSku !== art.sku ? rawSku : '');
|
||||
ean = art.ean || '';
|
||||
trackStock = Number(art.track_stock ?? 0) === 1;
|
||||
@@ -1036,6 +1041,8 @@ export async function createAndAttachManifestPdf(googleAuthId, companyId, manife
|
||||
const stockRes = await store.provider.query(stockSql, { companyId, ownSku, articleId }).catch(() => ({ rows: [] }));
|
||||
currentStock = Number(stockRes.rows?.[0]?.stock ?? 0);
|
||||
}
|
||||
} else {
|
||||
supplierSku = rawSku;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1058,6 +1065,8 @@ export async function createAndAttachManifestPdf(googleAuthId, companyId, manife
|
||||
return {
|
||||
...line,
|
||||
ownSku,
|
||||
ownArticleName,
|
||||
articleName: ownArticleName,
|
||||
supplierSku,
|
||||
ean,
|
||||
trackStock,
|
||||
|
||||
Reference in New Issue
Block a user