feat: Etiketten-Seitenlayout auf dem A4-Bogen frei waehlbar
- LabelTemplate bekommt columns/rows (optional, leer = automatisch passend), plus konfigurierbare Raender/Abstaende - damit ein Etikett exakt auf das vorgedruckte Raster eines physischen Etikettenbogens (z.B. Avery) gelegt werden kann statt nur automatisch berechnet - Startposition beim Drucken waehlbar, fuer bereits angebrochene Boegen (erste Seite startet ab der gewaehlten Position, Folgeseiten wieder von vorne)
This commit is contained in:
1 parent
9659b8d266
commit
c6941a797f
11 files changed
+357
-27
No files matched your search
@@ -64,6 +64,12 @@ describe('LabelTemplatesService', () => {
|
||||
elements,
|
||||
widthMm: 90,
|
||||
heightMm: 35,
|
||||
columns: null,
|
||||
rows: null,
|
||||
marginTopMm: 5,
|
||||
marginLeftMm: 5,
|
||||
gapXMm: 2,
|
||||
gapYMm: 2,
|
||||
isDefault: false,
|
||||
active: true,
|
||||
};
|
||||
@@ -213,5 +219,56 @@ describe('LabelTemplatesService', () => {
|
||||
// A PDF with an embedded raster image contains an XObject /Image entry.
|
||||
expect(pdf.toString('latin1')).toContain('/Image');
|
||||
});
|
||||
|
||||
function countPages(pdf: Buffer): number {
|
||||
const matches = pdf.toString('latin1').match(/\/Type\s*\/Page[^s]/g);
|
||||
return matches ? matches.length : 0;
|
||||
}
|
||||
|
||||
it('uses an explicit columns/rows override instead of auto-fitting', async () => {
|
||||
prisma.labelTemplate.findUnique.mockResolvedValue({
|
||||
...template,
|
||||
columns: 1,
|
||||
rows: 1,
|
||||
});
|
||||
prisma.bottlingBatch.findUnique.mockResolvedValue({
|
||||
id: 'batch-1',
|
||||
jarSize: 500,
|
||||
jarCount: 3,
|
||||
lotNumber: 'L-001',
|
||||
date: new Date('2026-06-01T00:00:00.000Z'),
|
||||
bestBeforeDate: new Date('2028-06-01T00:00:00.000Z'),
|
||||
honeyBatch: { batchNumber: 'HB-001', honeyType: 'Bluetenhonig' },
|
||||
product: { name: 'Glas 500g' },
|
||||
});
|
||||
|
||||
const pdf = await service.renderLabelsPdf('template-1', 'batch-1');
|
||||
|
||||
expect(countPages(pdf)).toBe(3);
|
||||
});
|
||||
|
||||
it('skips already-used slots on the first sheet via startPosition, but not later sheets', async () => {
|
||||
prisma.labelTemplate.findUnique.mockResolvedValue({
|
||||
...template,
|
||||
columns: 2,
|
||||
rows: 1,
|
||||
});
|
||||
prisma.bottlingBatch.findUnique.mockResolvedValue({
|
||||
id: 'batch-1',
|
||||
jarSize: 500,
|
||||
jarCount: 3,
|
||||
lotNumber: 'L-001',
|
||||
date: new Date('2026-06-01T00:00:00.000Z'),
|
||||
bestBeforeDate: new Date('2028-06-01T00:00:00.000Z'),
|
||||
honeyBatch: { batchNumber: 'HB-001', honeyType: 'Bluetenhonig' },
|
||||
product: { name: 'Glas 500g' },
|
||||
});
|
||||
|
||||
const pdf = await service.renderLabelsPdf('template-1', 'batch-1', 2);
|
||||
|
||||
// perPage=2, skip=1: label 1 fills the remaining slot on page 1,
|
||||
// labels 2-3 fill both slots of page 2.
|
||||
expect(countPages(pdf)).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user