From 1912b5b48dfcd25bbfc6040347a32e134ac04eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Chudy?= Date: Wed, 3 Dec 2025 13:42:56 +0100 Subject: [PATCH] fix build config & fixes for invoice FA1/FA2/FA3 --- package-lock.json | 4 +- package.json | 14 +- src/index.ts | 2 +- .../generators/FA1/Adnotacje.spec.ts | 1 + src/lib-public/generators/FA1/Adnotacje.ts | 3 +- .../generators/FA1/DodatkoweInformacje.ts | 15 +- .../generators/FA1/Podmiot1.spec.ts | 12 +- src/lib-public/generators/FA1/Podmiot1.ts | 19 +- .../generators/FA1/Podmiot1Podmiot1K.spec.ts | 1 + .../generators/FA1/Podmiot1Podmiot1K.ts | 6 +- .../generators/FA1/Podmiot2.spec.ts | 2 +- src/lib-public/generators/FA1/Podmiot2.ts | 2 +- .../generators/FA1/Podmiot2Podmiot2k.spec.ts | 1 + .../generators/FA1/Podmiot2Podmiot2k.ts | 6 +- .../generators/FA1/Podmiot3.spec.ts | 4 +- src/lib-public/generators/FA1/Podmiot3.ts | 2 +- .../generators/FA1/PodmiotUpowazniony.ts | 2 +- .../generators/FA1/Podmioty.spec.ts | 1 + src/lib-public/generators/FA1/Podmioty.ts | 8 +- .../generators/FA1/RachunekBankowy.spec.ts | 242 ++++++++++++++++ .../generators/FA1/RachunekBankowy.ts | 27 +- .../generators/FA2/Adnotacje.spec.ts | 11 +- src/lib-public/generators/FA2/Adnotacje.ts | 3 +- .../FA2/DodatkoweInformacje.spec.ts | 14 +- .../generators/FA2/DodatkoweInformacje.ts | 15 +- .../generators/FA2/Podmiot1.spec.ts | 16 +- src/lib-public/generators/FA2/Podmiot1.ts | 12 +- .../generators/FA2/Podmiot1Podmiot1K.spec.ts | 9 +- .../generators/FA2/Podmiot1Podmiot1K.ts | 14 +- .../generators/FA2/Podmiot1Podmiot1K2.spec.ts | 29 +- .../generators/FA2/Podmiot2.spec.ts | 6 +- src/lib-public/generators/FA2/Podmiot2.ts | 2 +- .../generators/FA2/Podmiot2Podmiot2k.spec.ts | 18 +- .../generators/FA2/Podmiot2Podmiot2k.ts | 14 +- src/lib-public/generators/FA2/Podmiot3.ts | 2 +- .../FA2/PodmiotDaneKontaktowe.spec.ts | 4 +- .../generators/FA2/PodmiotDaneKontaktowe.ts | 2 +- .../generators/FA2/Podmioty.spec.ts | 1 + src/lib-public/generators/FA2/Podmioty.ts | 8 +- .../generators/FA2/RachunekBankowy.spec.ts | 259 +++++++++++++++++ .../generators/FA2/RachunekBankowy.ts | 29 +- .../generators/FA3/Adnotacje.spec.ts | 8 +- src/lib-public/generators/FA3/Adnotacje.ts | 3 +- .../FA3/DodatkoweInformacje.spec.ts | 13 + .../generators/FA3/DodatkoweInformacje.ts | 15 +- src/lib-public/generators/FA3/Platnosc.ts | 10 +- .../generators/FA3/Podmiot1.spec.ts | 16 +- src/lib-public/generators/FA3/Podmiot1.ts | 12 +- .../generators/FA3/Podmiot1Podmiot1K.spec.ts | 7 +- .../generators/FA3/Podmiot1Podmiot1K.ts | 14 +- .../generators/FA3/Podmiot2.spec.ts | 7 +- src/lib-public/generators/FA3/Podmiot2.ts | 2 +- .../generators/FA3/Podmiot2Podmiot2k.spec.ts | 11 +- .../generators/FA3/Podmiot2Podmiot2k.ts | 11 +- src/lib-public/generators/FA3/Podmiot3.ts | 2 +- .../FA3/PodmiotDaneKontaktowe.spec.ts | 4 +- .../generators/FA3/PodmiotDaneKontaktowe.ts | 2 +- .../generators/FA3/Podmioty.spec.ts | 1 + src/lib-public/generators/FA3/Podmioty.ts | 8 +- .../generators/FA3/RachunekBankowy.spec.ts | 263 ++++++++++++++++++ .../generators/FA3/RachunekBankowy.ts | 29 +- .../generators/FA3/WarunkiTransakcji.spec.ts | 8 +- .../generators/FA3/WarunkiTransakcji.ts | 10 +- .../generators/common/Rozliczenie.spec.ts | 1 + .../generators/common/Rozliczenie.ts | 11 +- src/shared/PDF-functions.spec.ts | 2 +- src/shared/PDF-functions.ts | 52 +++- src/shared/consts/const.ts | 7 + 68 files changed, 1144 insertions(+), 227 deletions(-) create mode 100644 src/lib-public/generators/FA1/RachunekBankowy.spec.ts create mode 100644 src/lib-public/generators/FA2/RachunekBankowy.spec.ts create mode 100644 src/lib-public/generators/FA3/RachunekBankowy.spec.ts diff --git a/package-lock.json b/package-lock.json index f78d99b..9e27f1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@akmf/ksef-fe-invoice-converter", - "version": "0.0.30", + "version": "0.0.32", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@akmf/ksef-fe-invoice-converter", - "version": "0.0.30", + "version": "0.0.32", "license": "ISC", "dependencies": { "pdfmake": "^0.2.20", diff --git a/package.json b/package.json index fb6134d..f3141cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@akmf/ksef-fe-invoice-converter", - "version": "0.0.30", + "version": "0.0.32", "scripts": { "dev": "vite --mode public --config vite.config.ts", "build": "vite build --mode production", @@ -9,15 +9,15 @@ "test:ui": "vitest --ui", "test:ci": "vitest run --coverage" }, - "main": "./ksef-fe-invoice-converter.umd.js", - "module": "./ksef-fe-invoice-converter.es.js", - "types": "./src/lib/index.d.ts", + "main": "./ksef-fe-invoice-converter.umd.cjs", + "module": "./ksef-fe-invoice-converter.js", + "types": "./index.d.ts", "type": "module", "exports": { ".": { - "types": "./src/lib/index.d.ts", - "import": "./ksef-fe-invoice-converter.es.js", - "require": "./ksef-fe-invoice-converter.umd.js" + "types": "./index.d.ts", + "import": "./ksef-fe-invoice-converter.js", + "require": "./ksef-fe-invoice-converter.umd.cjs" } }, "keywords": [], diff --git a/src/index.ts b/src/index.ts index 6e9847a..8c52e06 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1 @@ -export { generateInvoice, generatePDFUPO } from './lib-public'; \ No newline at end of file +export { generateInvoice, generatePDFUPO } from './lib-public'; diff --git a/src/lib-public/generators/FA1/Adnotacje.spec.ts b/src/lib-public/generators/FA1/Adnotacje.spec.ts index 9914a59..11f8fd9 100644 --- a/src/lib-public/generators/FA1/Adnotacje.spec.ts +++ b/src/lib-public/generators/FA1/Adnotacje.spec.ts @@ -8,6 +8,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ formatText: vi.fn().mockImplementation((text) => ({ text })), hasValue: vi.fn((val) => Boolean(val && val._text)), verticalSpacing: vi.fn().mockImplementation((size) => ({ text: `SPACING:${size}` })), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); describe(generateAdnotacje.name, () => { diff --git a/src/lib-public/generators/FA1/Adnotacje.ts b/src/lib-public/generators/FA1/Adnotacje.ts index 9de2df0..fc53a08 100644 --- a/src/lib-public/generators/FA1/Adnotacje.ts +++ b/src/lib-public/generators/FA1/Adnotacje.ts @@ -3,6 +3,7 @@ import { createHeader, createLabelText, formatText, + generateColumns, hasValue, verticalSpacing, } from '../../../shared/PDF-functions'; @@ -120,7 +121,7 @@ export function generateAdnotacje(adnotacje?: Adnotacje): Content[] { } if (firstColumn.length || secondColumn.length) { - result.push({ columns: [firstColumn, secondColumn], columnGap: 20 }); + result.push(generateColumns([firstColumn, secondColumn])); } if (result.length) { diff --git a/src/lib-public/generators/FA1/DodatkoweInformacje.ts b/src/lib-public/generators/FA1/DodatkoweInformacje.ts index 4b2d055..788c532 100644 --- a/src/lib-public/generators/FA1/DodatkoweInformacje.ts +++ b/src/lib-public/generators/FA1/DodatkoweInformacje.ts @@ -14,15 +14,20 @@ import FormatTyp from '../../../shared/enums/common.enum'; import { FakturaZaliczkowa, TableWithFields } from '../../types/fa1-additional-types'; export function generateDodatkoweInformacje(faVat: Fa): Content[] { - const tpLabel1: Content[] = []; - const tpLabel2: Content[] = []; + const tpLabel: Content[] = []; if (getValue(faVat.TP) === '1') { - tpLabel1.push( + tpLabel.push( formatText('- Istniejące powiązania między nabywcą a dokonującym dostawy towarów lub usługodawcą') ); - tpLabel2.push(formatText('- Faktura, o której mowa w art. 109 ust. 3d ustawy')); } + + const fpLabel: Content[] = []; + + if (getValue(faVat.FP) === '1') { + fpLabel.push(formatText('- Faktura, o której mowa w art. 109 ust. 3d ustawy')); + } + const zwrotAkcyzyLabel: Content[] = []; if (getValue(faVat.ZwrotAkcyzy) === '1') { @@ -33,7 +38,7 @@ export function generateDodatkoweInformacje(faVat: Fa): Content[] { ); } - const labels: Content[][] = [tpLabel1, tpLabel2, zwrotAkcyzyLabel].filter((el) => el.length > 0); + const labels: Content[][] = [tpLabel, fpLabel, zwrotAkcyzyLabel].filter((el) => el.length > 0); const table: Content[] = [ ...createHeader('Dodatkowe informacje'), ...labels, diff --git a/src/lib-public/generators/FA1/Podmiot1.spec.ts b/src/lib-public/generators/FA1/Podmiot1.spec.ts index c9a8144..3cc7faa 100644 --- a/src/lib-public/generators/FA1/Podmiot1.spec.ts +++ b/src/lib-public/generators/FA1/Podmiot1.spec.ts @@ -9,6 +9,8 @@ vi.mock('../../../shared/PDF-functions', () => ({ })), formatText: vi.fn((text: string, _args?: any) => ({ text: `FMT:${text}` })), getTable: vi.fn((data) => data || []), + getValue: vi.fn((val) => val?._text || ''), + hasValue: vi.fn((val) => Boolean(val && val._text)), })); vi.mock('./PodmiotAdres', () => ({ generatePodmiotAdres: vi.fn((adres: any, label: string) => ({ adr: `${label}` })), @@ -33,7 +35,7 @@ describe('generatePodmiot1', () => { expect(result).toEqual( expect.arrayContaining([ { text: 'HEADER:Sprzedawca' }, - { text: 'LABEL:NrEORI: EORI123' }, + { text: 'LABEL:Numer EORI: EORI123' }, { text: 'LABEL:Prefiks VAT: PL' }, ]) ); @@ -66,7 +68,7 @@ describe('generatePodmiot1', () => { NrEORI: { _text: 'xxx' }, PrefiksPodatnika: { _text: 'PL' }, Email: { _text: 'a@b.pl' }, - StatusInfoPodatnika: { _text: 'zarejestrowany' }, + StatusInfoPodatnika: { _text: '2' }, }; const result = generatePodmiot1(podmiot1); @@ -74,7 +76,7 @@ describe('generatePodmiot1', () => { expect.arrayContaining([ { text: 'FMT:Dane kontaktowe' }, { contact: 'KONTAKT' }, - { text: 'LABEL:Status podatnika: zarejestrowany' }, + { text: 'LABEL:Status podatnika: Postępowanie restrukturyzacyjne' }, ]) ); }); @@ -83,10 +85,10 @@ describe('generatePodmiot1', () => { const podmiot1: Podmiot1 = { NrEORI: { _text: 'xxx' }, PrefiksPodatnika: { _text: 'PL' }, - StatusInfoPodatnika: { _text: 'SAMO' }, + StatusInfoPodatnika: { _text: '1' }, }; const result = generatePodmiot1(podmiot1); - expect(result).toEqual(expect.arrayContaining([{ text: 'LABEL:Status podatnika: SAMO' }])); + expect(result).toEqual(expect.arrayContaining([{ text: 'LABEL:Status podatnika: Stan likwidacji' }])); }); }); diff --git a/src/lib-public/generators/FA1/Podmiot1.ts b/src/lib-public/generators/FA1/Podmiot1.ts index 213591c..51716f6 100644 --- a/src/lib-public/generators/FA1/Podmiot1.ts +++ b/src/lib-public/generators/FA1/Podmiot1.ts @@ -1,16 +1,24 @@ import { Content } from 'pdfmake/interfaces'; -import { createHeader, createLabelText, formatText, getTable } from '../../../shared/PDF-functions'; +import { + createHeader, + createLabelText, + formatText, + getTable, + getValue, + hasValue, +} from '../../../shared/PDF-functions'; import FormatTyp from '../../../shared/enums/common.enum'; import { Podmiot1 } from '../../types/fa1.types'; import { generatePodmiotAdres } from './PodmiotAdres'; import { generateDaneIdentyfikacyjne } from './PodmiotDaneIdentyfikacyjne'; import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe'; +import { TAXPAYER_STATUS } from '../../../shared/consts/const'; export function generatePodmiot1(podmiot1: Podmiot1): Content[] { const result: Content[] = createHeader('Sprzedawca'); result.push( - createLabelText('NrEORI: ', podmiot1.NrEORI), + createLabelText('Numer EORI: ', podmiot1.NrEORI), createLabelText('Prefiks VAT: ', podmiot1.PrefiksPodatnika) ); if (podmiot1.DaneIdentyfikacyjne) { @@ -30,10 +38,11 @@ export function generatePodmiot1(podmiot1: Podmiot1): Content[] { formatText('Dane kontaktowe', [FormatTyp.Label, FormatTyp.LabelMargin]), ...generateDaneKontaktowe(podmiot1.Email, getTable(podmiot1.Telefon)) ); + } + if (hasValue(podmiot1.StatusInfoPodatnika)) { + const statusInfo: string = TAXPAYER_STATUS[getValue(podmiot1.StatusInfoPodatnika)!]; - result.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika)); - } else if (podmiot1.StatusInfoPodatnika) { - result.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika)); + result.push(createLabelText('Status podatnika: ', statusInfo)); } return result; } diff --git a/src/lib-public/generators/FA1/Podmiot1Podmiot1K.spec.ts b/src/lib-public/generators/FA1/Podmiot1Podmiot1K.spec.ts index 69f2ef7..7b68086 100644 --- a/src/lib-public/generators/FA1/Podmiot1Podmiot1K.spec.ts +++ b/src/lib-public/generators/FA1/Podmiot1Podmiot1K.spec.ts @@ -11,6 +11,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ createSubHeader: vi.fn((label: string) => ({ text: `SUBHEADER:${label}` })), verticalSpacing: vi.fn((v: number) => ({ text: `SPACING:${v}` })), getTable: vi.fn((data) => data || []), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); vi.mock('./PodmiotAdres', () => ({ generatePodmiotAdres: vi.fn((adres: any, label: string) => ({ adr: label })), diff --git a/src/lib-public/generators/FA1/Podmiot1Podmiot1K.ts b/src/lib-public/generators/FA1/Podmiot1Podmiot1K.ts index 4095f29..90c9d04 100644 --- a/src/lib-public/generators/FA1/Podmiot1Podmiot1K.ts +++ b/src/lib-public/generators/FA1/Podmiot1Podmiot1K.ts @@ -3,6 +3,7 @@ import { createHeader, createLabelText, createSubHeader, + generateColumns, getTable, verticalSpacing, } from '../../../shared/PDF-functions'; @@ -42,10 +43,7 @@ export function generatePodmiot1Podmiot1K(podmiot1: Podmiot1, podmiot1K: Podmiot ); } if (firstColumn.length || secondColumn.length) { - result.push({ - columns: [firstColumn, secondColumn], - columnGap: 20, - }); + result.push(generateColumns([firstColumn, secondColumn])); } if (result.length) { result.push(verticalSpacing(1)); diff --git a/src/lib-public/generators/FA1/Podmiot2.spec.ts b/src/lib-public/generators/FA1/Podmiot2.spec.ts index ca60a44..ae4de0e 100644 --- a/src/lib-public/generators/FA1/Podmiot2.spec.ts +++ b/src/lib-public/generators/FA1/Podmiot2.spec.ts @@ -32,7 +32,7 @@ describe('generatePodmiot2', () => { const result = generatePodmiot2(podmiot2); expect(result).toEqual( - expect.arrayContaining([{ text: 'HEADER:Nabywca' }, { text: 'LABEL:NrEORI: EORI777' }]) + expect.arrayContaining([{ text: 'HEADER:Nabywca' }, { text: 'LABEL:Numer EORI: EORI777' }]) ); }); diff --git a/src/lib-public/generators/FA1/Podmiot2.ts b/src/lib-public/generators/FA1/Podmiot2.ts index 34b2935..7a7d320 100644 --- a/src/lib-public/generators/FA1/Podmiot2.ts +++ b/src/lib-public/generators/FA1/Podmiot2.ts @@ -17,7 +17,7 @@ import { DaneIdentyfikacyjneTPodmiot2Dto } from '../../types/fa2-additional-type export function generatePodmiot2(podmiot2: Podmiot2): Content[] { const result: Content[] = createHeader('Nabywca'); - result.push(createLabelText('NrEORI: ', podmiot2.NrEORI)); + result.push(createLabelText('Numer EORI: ', podmiot2.NrEORI)); if (hasValue(podmiot2.PrefiksNabywcy)) { result.push(createLabelText('Prefiks VAT: ', podmiot2.PrefiksNabywcy)); } diff --git a/src/lib-public/generators/FA1/Podmiot2Podmiot2k.spec.ts b/src/lib-public/generators/FA1/Podmiot2Podmiot2k.spec.ts index 927b57b..ff6ec3b 100644 --- a/src/lib-public/generators/FA1/Podmiot2Podmiot2k.spec.ts +++ b/src/lib-public/generators/FA1/Podmiot2Podmiot2k.spec.ts @@ -13,6 +13,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ getTable: vi.fn((arr) => arr || []), getValue: vi.fn((val) => (val && val._text ? val._text : '')), hasValue: vi.fn((val) => Boolean(val && val._text)), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); vi.mock('./PodmiotAdres', () => ({ generatePodmiotAdres: vi.fn((adres, label) => ({ adr: label })), diff --git a/src/lib-public/generators/FA1/Podmiot2Podmiot2k.ts b/src/lib-public/generators/FA1/Podmiot2Podmiot2k.ts index b086b27..370e592 100644 --- a/src/lib-public/generators/FA1/Podmiot2Podmiot2k.ts +++ b/src/lib-public/generators/FA1/Podmiot2Podmiot2k.ts @@ -3,6 +3,7 @@ import { createHeader, createLabelText, createSubHeader, + generateColumns, getTable, getValue, hasValue, @@ -44,10 +45,7 @@ export function generatePodmiot2Podmiot2K(podmiot2: Podmiot2, podmiot2K: Podmiot } if (firstColumn.length || secondColumn.length) { - result.push({ - columns: [firstColumn, secondColumn], - columnGap: 20, - }); + result.push(generateColumns([firstColumn, secondColumn])); } if (result.length) { result.push(verticalSpacing(1)); diff --git a/src/lib-public/generators/FA1/Podmiot3.spec.ts b/src/lib-public/generators/FA1/Podmiot3.spec.ts index b35b77e..563e581 100644 --- a/src/lib-public/generators/FA1/Podmiot3.spec.ts +++ b/src/lib-public/generators/FA1/Podmiot3.spec.ts @@ -40,7 +40,7 @@ describe('generatePodmiot3', () => { expect(last.left).toEqual( expect.arrayContaining([ { text: 'HEADER:Podmiot inny 1' }, - { text: 'LABEL:NrEORI: 999' }, + { text: 'LABEL:Numer EORI: 999' }, [{ text: 'LABEL:Rola: SPRZEDAWCA' }, { text: 'LABEL:Rola inna: ' }, { text: 'LABEL:Udział: ' }], ]) ); @@ -60,7 +60,7 @@ describe('generatePodmiot3', () => { expect(col1).toEqual( expect.arrayContaining([ { text: 'HEADER:Podmiot inny 2' }, - { text: 'LABEL:NrEORI: 1000' }, + { text: 'LABEL:Numer EORI: 1000' }, { text: 'LABEL:Identyfikator podatkowy inny: TAXX' }, { text: 'LABEL:Brak identyfikatora ' }, { id: 'ID' }, diff --git a/src/lib-public/generators/FA1/Podmiot3.ts b/src/lib-public/generators/FA1/Podmiot3.ts index cc37773..4c3b092 100644 --- a/src/lib-public/generators/FA1/Podmiot3.ts +++ b/src/lib-public/generators/FA1/Podmiot3.ts @@ -21,7 +21,7 @@ export function generatePodmiot3(podmiot: Podmiot3, index: number): Content[] { const column1: Content[] = [ ...createHeader(`Podmiot inny ${index + 1}`), - createLabelText('NrEORI: ', podmiot.NrEORI), + createLabelText('Numer EORI: ', podmiot.NrEORI), ]; if (hasValue(podmiot.DaneIdentyfikacyjne?.NrID)) { diff --git a/src/lib-public/generators/FA1/PodmiotUpowazniony.ts b/src/lib-public/generators/FA1/PodmiotUpowazniony.ts index aa9d028..82c38cd 100644 --- a/src/lib-public/generators/FA1/PodmiotUpowazniony.ts +++ b/src/lib-public/generators/FA1/PodmiotUpowazniony.ts @@ -27,7 +27,7 @@ export function generatePodmiotUpowazniony(podmiot: PodmiotUpowazniony | undefin columnLeft.push(createLabelText('Rola: ', getRolaUpowaznionegoString(podmiot.RolaPU, 1))); } if (hasValue(podmiot.NrEORI)) { - columnLeft.push(createLabelText('NrEORI: ', podmiot.NrEORI)); + columnLeft.push(createLabelText('Numer EORI: ', podmiot.NrEORI)); } if (podmiot.DaneIdentyfikacyjne) { if (hasValue(podmiot.DaneIdentyfikacyjne.NrID)) { diff --git a/src/lib-public/generators/FA1/Podmioty.spec.ts b/src/lib-public/generators/FA1/Podmioty.spec.ts index c594c08..d002536 100644 --- a/src/lib-public/generators/FA1/Podmioty.spec.ts +++ b/src/lib-public/generators/FA1/Podmioty.spec.ts @@ -7,6 +7,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ getTable: vi.fn((obj) => (obj ? (Array.isArray(obj) ? obj : [obj]) : [])), getValue: vi.fn((val) => (val && val._text ? val._text : '')), hasValue: vi.fn((val) => Boolean(val && val._text)), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); vi.mock('./Podmiot1', () => ({ generatePodmiot1: vi.fn(() => [{ podmiot1: true }]), diff --git a/src/lib-public/generators/FA1/Podmioty.ts b/src/lib-public/generators/FA1/Podmioty.ts index d0b35ba..8512c72 100644 --- a/src/lib-public/generators/FA1/Podmioty.ts +++ b/src/lib-public/generators/FA1/Podmioty.ts @@ -1,5 +1,5 @@ import { Content } from 'pdfmake/interfaces'; -import { createSection, getTable, getValue } from '../../../shared/PDF-functions'; +import { createSection, generateColumns, getTable, getValue } from '../../../shared/PDF-functions'; import { Faktura, Podmiot2K, Podmiot3 } from '../../types/fa1.types'; import { Podmiot3Podmiot2KDto } from '../../types/fa1-additional-types'; import { generatePodmiot1 } from './Podmiot1'; @@ -31,10 +31,10 @@ export function generatePodmioty(invoice: Faktura): Content[] { } } else { result.push([ - { - columns: [generatePodmiot1(invoice.Podmiot1!), generatePodmiot2(invoice.Podmiot2!)], + generateColumns([generatePodmiot1(invoice.Podmiot1!), generatePodmiot2(invoice.Podmiot2!)], { margin: [0, 0, 0, 8], - }, + columnGap: 20, + }), ]); } diff --git a/src/lib-public/generators/FA1/RachunekBankowy.spec.ts b/src/lib-public/generators/FA1/RachunekBankowy.spec.ts new file mode 100644 index 0000000..d4145be --- /dev/null +++ b/src/lib-public/generators/FA1/RachunekBankowy.spec.ts @@ -0,0 +1,242 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { generujRachunekBankowy } from './RachunekBankowy'; +import * as PDFFunctions from '../../../shared/PDF-functions'; +import FormatTyp from '../../../shared/enums/common.enum'; +import * as CommonFunctions from '../../../shared/generators/common/functions'; +import { makeBreakable } from '../../../shared/PDF-functions'; + +vi.mock('../../../shared/PDF-functions', () => ({ + createHeader: vi.fn(), + createSection: vi.fn(), + formatText: vi.fn(), + makeBreakable: vi.fn(), + getValue: vi.fn((val) => (val && val._text ? val._text : '')), + hasValue: vi.fn((val) => Boolean(val && val._text)), +})); + +vi.mock('../../../shared/generators/common/functions', () => ({ + getTypRachunkowWlasnych: vi.fn(), +})); + +describe(generujRachunekBankowy.name, () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + const mockAccount: any = { + NrRB: { _text: '12345678901234567890123456' }, + SWIFT: { _text: 'BPKOPLPW' }, + RachunekWlasnyBanku: { _text: '1' }, + NazwaBanku: { _text: 'PKO Bank Polski' }, + OpisRachunku: { _text: 'Rachunek główny' }, + } as any; + + beforeEach(() => { + vi.mocked(PDFFunctions.createHeader).mockReturnValue(['header'] as any); + vi.mocked(PDFFunctions.createSection).mockReturnValue('section' as any); + vi.mocked(PDFFunctions.formatText).mockReturnValue('formatted' as any); + vi.mocked(CommonFunctions.getTypRachunkowWlasnych).mockReturnValue('Tak'); + }); + + describe('when accounts is undefined or empty', () => { + it('should return empty array when accounts is undefined', () => { + const result = generujRachunekBankowy(undefined, 'Rachunek bankowy'); + + expect(result).toEqual([]); + }); + + it('should return empty array when accounts is empty array', () => { + const result = generujRachunekBankowy([], 'Rachunek bankowy'); + + expect(result).toEqual([]); + }); + }); + + describe('when accounts exist', () => { + it('should call createHeader with provided title', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Rachunek bankowy ', [0, 12, 0, 8]); + }); + + it('should call createHeader with empty string when title is not provided', () => { + generujRachunekBankowy([mockAccount]); + + expect(PDFFunctions.createHeader).toHaveBeenCalledWith('', [0, 12, 0, 8]); + }); + + it('should call createSection and return result', () => { + const mockSection = 'section'; + + vi.mocked(PDFFunctions.createSection).mockReturnValue(mockSection as any); + + const result = generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.createSection).toHaveBeenCalledWith(expect.any(Array), false); + expect(result).toEqual(mockSection); + }); + + it('should format "Kod SWIFT" field', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Kod SWIFT', FormatTyp.GrayBoldTitle); + expect(PDFFunctions.formatText).toHaveBeenCalledWith(mockAccount.SWIFT?._text, FormatTyp.Default); + }); + + it('should format "Rachunek własny banku" field', () => { + vi.mocked(CommonFunctions.getTypRachunkowWlasnych).mockReturnValue('Tak'); + + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Rachunek własny banku', FormatTyp.GrayBoldTitle); + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledWith(mockAccount.RachunekWlasnyBanku); + expect(PDFFunctions.formatText).toHaveBeenCalledWith(makeBreakable('Tak'), FormatTyp.Default); + }); + + it('should format "Nazwa banku" field', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Nazwa banku', FormatTyp.GrayBoldTitle); + expect(PDFFunctions.formatText).toHaveBeenCalledWith( + makeBreakable(mockAccount.NazwaBanku?._text), + FormatTyp.Default + ); + }); + + it('should create table structure with correct widths', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent).toHaveProperty('table'); + expect(tableContent.table).toHaveProperty('widths', ['*', 'auto']); + }); + + it('should create table structure with unbreakable property', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent).toHaveProperty('unbreakable', true); + }); + + it('should create table with correct layout', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent).toHaveProperty('layout'); + expect(tableContent.layout).toHaveProperty('hLineWidth'); + expect(tableContent.layout).toHaveProperty('hLineColor'); + expect(tableContent.layout).toHaveProperty('vLineWidth'); + expect(tableContent.layout).toHaveProperty('vLineColor'); + }); + + it('should create table with correct line colors', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent.layout.hLineColor()).toBe('#BABABA'); + expect(tableContent.layout.vLineColor()).toBe('#BABABA'); + }); + + it('should create table with correct line widths', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent.layout.hLineWidth()).toBe(1); + expect(tableContent.layout.vLineWidth()).toBe(1); + }); + + it('should handle account with undefined fields', () => { + const accountWithUndefined: any = { + NrRB: { _text: undefined }, + SWIFT: { _text: undefined }, + RachunekWlasnyBanku: { _text: undefined }, + NazwaBanku: { _text: undefined }, + OpisRachunku: { _text: undefined }, + } as any; + + generujRachunekBankowy([accountWithUndefined], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith(undefined, FormatTyp.Default); + }); + }); + + describe('when multiple accounts exist', () => { + it('should create multiple tables for multiple accounts', () => { + const account2: any = { + NrRB: { _text: '98765432109876543210987654' }, + SWIFT: { _text: 'PKOPPLPW' }, + RachunekWlasnyBanku: { _text: '0' }, + NazwaBanku: { _text: 'mBank' }, + OpisRachunku: { _text: 'Rachunek pomocniczy' }, + } as any; + + generujRachunekBankowy([mockAccount, account2], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + + expect(sectionCall.length).toBe(2); + }); + + it('should call getTypRachunkowWlasnych for each account', () => { + const account2: any = { + NrRB: { _text: '98765432109876543210987654' }, + SWIFT: { _text: 'PKOPPLPW' }, + RachunekWlasnyBanku: { _text: '0' }, + NazwaBanku: { _text: 'mBank' }, + OpisRachunku: { _text: 'Rachunek pomocniczy' }, + } as any; + + generujRachunekBankowy([mockAccount, account2], 'Rachunek bankowy'); + + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledTimes(2); + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledWith(mockAccount.RachunekWlasnyBanku); + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledWith(account2.RachunekWlasnyBanku); + }); + + it('should format all fields for all accounts', () => { + const account2: any = { + NrRB: { _text: '98765432109876543210987654' }, + SWIFT: { _text: 'PKOPPLPW' }, + RachunekWlasnyBanku: { _text: '0' }, + NazwaBanku: { _text: 'mBank' }, + OpisRachunku: { _text: 'Rachunek pomocniczy' }, + } as any; + + generujRachunekBankowy([mockAccount, account2], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Kod SWIFT', FormatTyp.GrayBoldTitle); + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Kod SWIFT', FormatTyp.GrayBoldTitle); + }); + }); + + describe('table structure', () => { + it('should create table with 5 rows', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent.table.body.length).toBe(3); + }); + + it('should include header in result array', () => { + vi.mocked(PDFFunctions.createHeader).mockReturnValue(['header-content'] as any); + + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + + expect(sectionCall[0][0]).toBe('header-content'); + }); + }); +}); diff --git a/src/lib-public/generators/FA1/RachunekBankowy.ts b/src/lib-public/generators/FA1/RachunekBankowy.ts index db7d90a..22c1bdd 100644 --- a/src/lib-public/generators/FA1/RachunekBankowy.ts +++ b/src/lib-public/generators/FA1/RachunekBankowy.ts @@ -1,5 +1,12 @@ import { Content, ContentTable } from 'pdfmake/interfaces'; -import { createHeader, createSection, formatText } from '../../../shared/PDF-functions'; +import { + createHeader, + createSection, + formatText, + getValue, + hasValue, + makeBreakable, +} from '../../../shared/PDF-functions'; import FormatTyp from '../../../shared/enums/common.enum'; import { FP } from '../../types/fa1.types'; import { getTypRachunkowWlasnych } from '../../../shared/generators/common/functions'; @@ -22,40 +29,40 @@ export const generujRachunekBankowy: (accounts?: Record[], title?: s [0, 12, 0, 8] ); - if (account.NrRBZagr?._text) { + if (hasValue(account.NrRBZagr)) { table.push([ formatText('Format rachunku', FormatTyp.GrayBoldTitle), formatText('Zagraniczny', FormatTyp.Default), ]); - } else if (account.NrRBPL?._text) { + } else if (hasValue(account.NrRBPL)) { table.push([ formatText('Format rachunku', FormatTyp.GrayBoldTitle), formatText('Polski', FormatTyp.Default), ]); } - if (account.NrRBPL?._text) { + if (hasValue(account.NrRBPL)) { table.push([ formatText('Pełny numer rachunku w standardzie NRB', FormatTyp.GrayBoldTitle), - formatText(account.NrRBPL?._text, FormatTyp.Default), + formatText(getValue(account.NrRBPL), FormatTyp.Default), ]); } - if (account.NrRBZagr?._text) { + if (hasValue(account.NrRBZagr)) { table.push([ formatText('Pełny numer rachunku zagranicznego', FormatTyp.GrayBoldTitle), - formatText(account.NrRBZagr?._text, FormatTyp.Default), + formatText(getValue(account.NrRBZagr), FormatTyp.Default), ]); } table.push([ formatText('Kod SWIFT', FormatTyp.GrayBoldTitle), - formatText(account.SWIFT?._text, FormatTyp.Default), + formatText(getValue(account.SWIFT), FormatTyp.Default), ]); table.push([ formatText('Rachunek własny banku', FormatTyp.GrayBoldTitle), - formatText(getTypRachunkowWlasnych(account.RachunekWlasnyBanku), FormatTyp.Default), + formatText(makeBreakable(getTypRachunkowWlasnych(account.RachunekWlasnyBanku), 20), FormatTyp.Default), ]); table.push([ formatText('Nazwa banku', FormatTyp.GrayBoldTitle), - formatText(account.NazwaBanku?._text, FormatTyp.Default), + formatText(makeBreakable(getValue(account.NazwaBanku), 20), FormatTyp.Default), ]); result.push([ ...base, diff --git a/src/lib-public/generators/FA2/Adnotacje.spec.ts b/src/lib-public/generators/FA2/Adnotacje.spec.ts index a00d251..00133b9 100644 --- a/src/lib-public/generators/FA2/Adnotacje.spec.ts +++ b/src/lib-public/generators/FA2/Adnotacje.spec.ts @@ -9,6 +9,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ getTable: vi.fn(() => []), hasValue: vi.fn((v) => !!v?._text), verticalSpacing: vi.fn((n: number) => ({ text: `space-${n}` })), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); describe(generateAdnotacje.name, () => { @@ -114,9 +115,15 @@ describe(generateDostawy.name, () => { const result = generateAdnotacje(annotations); const flat = result.flatMap((r: any) => (Array.isArray(r.columns) ? r.columns.flat() : [r]))?.flat(); - expect(flat.some((c: any) => c.text?.includes('Directive'))).toBe(true); + expect( + flat.flatMap((c) => (Array.isArray(c) ? c : [c])).some((item) => item?.text?.includes('Directive')) + ).toBe(true); expect(flat.some((c: any) => c.text?.includes('Dostawa towarów lub świadczenie'))).toBe(true); - expect(flat.some((c: any) => c.text?.includes('Podstawa zwolnienia od podatku'))).toBe(true); + expect( + flat + .flatMap((c) => (Array.isArray(c) ? c : [c])) + .some((item) => item?.text?.includes('Podstawa zwolnienia od podatku')) + ).toBe(true); }); it('adds VAT-22 and calls generateDostawy', () => { diff --git a/src/lib-public/generators/FA2/Adnotacje.ts b/src/lib-public/generators/FA2/Adnotacje.ts index 442e15a..44839d8 100644 --- a/src/lib-public/generators/FA2/Adnotacje.ts +++ b/src/lib-public/generators/FA2/Adnotacje.ts @@ -3,6 +3,7 @@ import { createHeader, createLabelText, formatText, + generateColumns, getTable, hasValue, verticalSpacing, @@ -105,7 +106,7 @@ export function generateAdnotacje(adnotacje?: Adnotacje): Content[] { secondColumn.push({ text: 'Samofakturowanie' }); } if (firstColumn.length || secondColumn.length) { - result.push({ columns: [firstColumn, secondColumn], columnGap: 20 }); + result.push(generateColumns([firstColumn, secondColumn])); } if (result.length) { diff --git a/src/lib-public/generators/FA2/DodatkoweInformacje.spec.ts b/src/lib-public/generators/FA2/DodatkoweInformacje.spec.ts index 64b28c1..4a5a13c 100644 --- a/src/lib-public/generators/FA2/DodatkoweInformacje.spec.ts +++ b/src/lib-public/generators/FA2/DodatkoweInformacje.spec.ts @@ -1,6 +1,5 @@ import { describe, it, expect, vi, beforeEach, test } from 'vitest'; import { generateDodatkoweInformacje } from './DodatkoweInformacje'; -import FormatTyp from '../../../shared/enums/common.enum'; vi.mock('../../../shared/PDF-functions', () => ({ createHeader: vi.fn((text: string) => [{ text, style: 'header' }]), @@ -13,11 +12,9 @@ vi.mock('../../../shared/PDF-functions', () => ({ })); import { - createHeader, createSection, createSubHeader, formatText, - getValue, getTable, getContentTable, } from '../../../shared/PDF-functions'; @@ -79,4 +76,15 @@ describe(generateDodatkoweInformacje.name, () => { expect(createSection).toHaveBeenCalled(); expect(result.length).toBeGreaterThan(0); }); + + it('poprawnie dodaje sekcję FP', () => { + const faVat = { + FP: { _text: '1' }, + }; + const result = generateDodatkoweInformacje(faVat as any); + + expect(formatText).toHaveBeenCalledWith('- Faktura, o której mowa w art. 109 ust. 3d ustawy'); + expect(createSection).toHaveBeenCalled(); + expect(result.length).toBeGreaterThan(0); + }); }); diff --git a/src/lib-public/generators/FA2/DodatkoweInformacje.ts b/src/lib-public/generators/FA2/DodatkoweInformacje.ts index d8e7254..c6c3345 100644 --- a/src/lib-public/generators/FA2/DodatkoweInformacje.ts +++ b/src/lib-public/generators/FA2/DodatkoweInformacje.ts @@ -14,15 +14,20 @@ import FormatTyp from '../../../shared/enums/common.enum'; import { FormContentState } from '../../../shared/types/additional-data.types'; export function generateDodatkoweInformacje(faVat: Fa): Content[] { - const tpLabel1: Content[] = []; - const tpLabel2: Content[] = []; + const tpLabel: Content[] = []; if (getValue(faVat.TP) === '1') { - tpLabel1.push( + tpLabel.push( formatText('- Istniejące powiązania między nabywcą a dokonującym dostawy towarów lub usługodawcą') ); - tpLabel2.push(formatText('- Faktura, o której mowa w art. 109 ust. 3d ustawy')); } + + const fpLabel: Content[] = []; + + if (getValue(faVat.FP) === '1') { + fpLabel.push(formatText('- Faktura, o której mowa w art. 109 ust. 3d ustawy')); + } + const zwrotAkcyzyLabel: Content[] = []; if (getValue(faVat.ZwrotAkcyzy) === '1') { @@ -33,7 +38,7 @@ export function generateDodatkoweInformacje(faVat: Fa): Content[] { ); } - const labels: Content[][] = [tpLabel1, tpLabel2, zwrotAkcyzyLabel].filter( + const labels: Content[][] = [tpLabel, fpLabel, zwrotAkcyzyLabel].filter( (el: Content[]): boolean => el.length > 0 ); const table: Content[] = [ diff --git a/src/lib-public/generators/FA2/Podmiot1.spec.ts b/src/lib-public/generators/FA2/Podmiot1.spec.ts index 55f6501..b1ae411 100644 --- a/src/lib-public/generators/FA2/Podmiot1.spec.ts +++ b/src/lib-public/generators/FA2/Podmiot1.spec.ts @@ -11,6 +11,8 @@ vi.mock('../../../shared/PDF-functions', () => ({ createHeader: vi.fn((text: string): Content[] => [{ text, style: 'header' }]), createLabelText: vi.fn((label: string, value: any): Content[] => [{ text: `${label}${value ?? ''}` }]), formatText: vi.fn((text: string, style?: any): Content => ({ text, style })), + getValue: vi.fn((val) => val?._text || ''), + hasValue: vi.fn((val) => Boolean(val && val._text)), })); vi.mock('./Adres', () => ({ @@ -40,7 +42,7 @@ describe(generatePodmiot1.name, (): void => { const result: Content[] = generatePodmiot1(podmiot as Podmiot1); expect(createHeader).toHaveBeenCalledWith('Sprzedawca'); - expect(createLabelText).toHaveBeenCalledWith('NrEORI: ', 'EORI123'); + expect(createLabelText).toHaveBeenCalledWith('Numer EORI: ', 'EORI123'); expect(createLabelText).toHaveBeenCalledWith('Prefiks VAT: ', 'PL'); expect((result as any[]).some((c) => c?.[0]?.text.includes('EORI123'))).toBe(true); }); @@ -72,29 +74,27 @@ describe(generatePodmiot1.name, (): void => { expect(formatText).toHaveBeenCalledWith('Adres do korespondencji', ['Label', 'LabelMargin']); }); - it('generates contact data and taxpayer status', (): void => { + it('generates contact data', (): void => { const podmiot: Partial = { DaneKontaktowe: [{ Telefon: { _text: '123' } }], - StatusInfoPodatnika: { _text: 'active' }, }; const result = generatePodmiot1(podmiot as Podmiot1); expect(generateDaneKontaktowe).toHaveBeenCalledWith([{ Telefon: { _text: '123' } }]); - expect(createLabelText).toHaveBeenCalledWith('Status podatnika: ', { _text: 'active' }); expect(result.some((c: Content): boolean => (c as any).text === 'mockDaneKontaktowe')).toBe(true); }); - it('generates only taxpayer status if no contact data', () => { + it('generates taxpayer status ', () => { const podmiot: Partial = { - StatusInfoPodatnika: { _text: 'inactive' }, + StatusInfoPodatnika: { _text: '1' }, }; const result: Content[] = generatePodmiot1(podmiot as Podmiot1); - expect(generateDaneKontaktowe).not.toHaveBeenCalled(); expect(createLabelText).toHaveBeenCalledWith( expect.stringContaining('Status podatnika'), - expect.objectContaining({ _text: 'inactive' }) + expect.stringContaining('Stan likwidacji') ); + expect(result.some((c: Content): boolean => (c as any).text === 'mockDaneKontaktowe')).toBe(false); }); }); diff --git a/src/lib-public/generators/FA2/Podmiot1.ts b/src/lib-public/generators/FA2/Podmiot1.ts index 2bde246..2790b52 100644 --- a/src/lib-public/generators/FA2/Podmiot1.ts +++ b/src/lib-public/generators/FA2/Podmiot1.ts @@ -1,16 +1,17 @@ import { Content } from 'pdfmake/interfaces'; -import { createHeader, createLabelText, formatText } from '../../../shared/PDF-functions'; +import { createHeader, createLabelText, formatText, getValue, hasValue } from '../../../shared/PDF-functions'; import { Podmiot1 } from '../../types/fa2.types'; import { generateAdres } from './Adres'; import { generateDaneIdentyfikacyjneTPodmiot1Dto } from './PodmiotDaneIdentyfikacyjneTPodmiot1Dto'; import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe'; import FormatTyp from '../../../shared/enums/common.enum'; +import { TAXPAYER_STATUS } from '../../../shared/consts/const'; export function generatePodmiot1(podmiot1: Podmiot1): Content[] { const result: Content[] = createHeader('Sprzedawca'); result.push( - createLabelText('NrEORI: ', podmiot1.NrEORI), + createLabelText('Numer EORI: ', podmiot1.NrEORI), createLabelText('Prefiks VAT: ', podmiot1.PrefiksPodatnika) ); if (podmiot1.DaneIdentyfikacyjne) { @@ -31,10 +32,11 @@ export function generatePodmiot1(podmiot1: Podmiot1): Content[] { formatText('Dane kontaktowe', [FormatTyp.Label, FormatTyp.LabelMargin]), ...generateDaneKontaktowe(podmiot1.DaneKontaktowe) ); + } + if (hasValue(podmiot1.StatusInfoPodatnika)) { + const statusInfo: string = TAXPAYER_STATUS[getValue(podmiot1.StatusInfoPodatnika)!]; - result.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika)); - } else if (podmiot1.StatusInfoPodatnika) { - result.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika)); + result.push(createLabelText('Status podatnika: ', statusInfo)); } return result; } diff --git a/src/lib-public/generators/FA2/Podmiot1Podmiot1K.spec.ts b/src/lib-public/generators/FA2/Podmiot1Podmiot1K.spec.ts index 1042864..20c58ff 100644 --- a/src/lib-public/generators/FA2/Podmiot1Podmiot1K.spec.ts +++ b/src/lib-public/generators/FA2/Podmiot1Podmiot1K.spec.ts @@ -10,6 +10,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ getTable: vi.fn((data: any) => data || []), formatText: vi.fn((text: string, style?: any): Content => ({ text, style })), verticalSpacing: vi.fn((margin: number) => ({ margin })), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); vi.mock('./Adres', () => ({ @@ -51,19 +52,15 @@ describe(generatePodmiot1Podmiot1K.name, () => { const result: any = generatePodmiot1Podmiot1K(podmiot1, podmiot1K); expect(result[0]).toEqual({ text: 'Sprzedawca', style: 'header' }); - expect(result[1]).toHaveProperty('columns'); expect(Array.isArray(result[1].columns[0])).toBe(true); expect(Array.isArray(result[1].columns[1])).toBe(true); expect(result[1].columns[0].length).toBeGreaterThan(0); expect(result[1].columns[1].length).toBe(0); - expect(result[2]).toHaveProperty('columns'); expect(Array.isArray(result[2].columns[0])).toBe(true); - expect(Array.isArray(result[2].columns[1])).toBe(true); + expect(Array.isArray(result[2].columns[1])).toBe(false); expect(result[2].columns[0].length).toBeGreaterThan(0); - expect(result[2].columns[1].length).toBeGreaterThan(0); - expect(result[3]).toEqual({ margin: 1 }); }); @@ -90,9 +87,7 @@ describe(generatePodmiot1Podmiot1K.name, () => { expect(result[1].columns[0]).toBeInstanceOf(Array); expect(result[1].columns[1]).toBeInstanceOf(Array); - expect(result[2].columns[0]).toBeInstanceOf(Array); - expect(result[2].columns[1]).toBeInstanceOf(Array); expect(result[3]).toEqual({ margin: 1 }); }); diff --git a/src/lib-public/generators/FA2/Podmiot1Podmiot1K.ts b/src/lib-public/generators/FA2/Podmiot1Podmiot1K.ts index 1c23901..1d5f8ad 100644 --- a/src/lib-public/generators/FA2/Podmiot1Podmiot1K.ts +++ b/src/lib-public/generators/FA2/Podmiot1Podmiot1K.ts @@ -3,6 +3,7 @@ import { createHeader, createLabelText, formatText, + generateColumns, getTable, verticalSpacing, } from '../../../shared/PDF-functions'; @@ -34,8 +35,8 @@ export function generatePodmiot1Podmiot1K(podmiot1: Podmiot1, podmiot1K: Podmiot columnGap: 20, }); } - firstColumn = generateCorrectedContent(podmiot1K); - secondColumn = generateCorrectedContent(podmiot1); + firstColumn = generateCorrectedContent(podmiot1K, 'Treść korygowana'); + secondColumn = generateCorrectedContent(podmiot1, 'Treść korygująca'); if (podmiot1.AdresKoresp) { secondColumn.push( @@ -44,10 +45,7 @@ export function generatePodmiot1Podmiot1K(podmiot1: Podmiot1, podmiot1K: Podmiot ); } if (firstColumn.length || secondColumn.length) { - result.push({ - columns: [firstColumn, secondColumn], - columnGap: 20, - }); + result.push(generateColumns([firstColumn, secondColumn])); } if (result.length) { result.push(verticalSpacing(1)); @@ -55,10 +53,10 @@ export function generatePodmiot1Podmiot1K(podmiot1: Podmiot1, podmiot1K: Podmiot return result; } -export function generateCorrectedContent(podmiot: Podmiot1 | Podmiot1K): Content[] { +export function generateCorrectedContent(podmiot: Podmiot1 | Podmiot1K, header: string): Content[] { const result: Content[] = []; - result.push(createHeader('Treść korygowana')); + result.push(createHeader(header)); if (podmiot.PrefiksPodatnika?._text) { result.push(createLabelText('Prefiks VAT: ', podmiot.PrefiksPodatnika)); diff --git a/src/lib-public/generators/FA2/Podmiot1Podmiot1K2.spec.ts b/src/lib-public/generators/FA2/Podmiot1Podmiot1K2.spec.ts index 1bd916d..024e499 100644 --- a/src/lib-public/generators/FA2/Podmiot1Podmiot1K2.spec.ts +++ b/src/lib-public/generators/FA2/Podmiot1Podmiot1K2.spec.ts @@ -8,6 +8,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ createLabelText: vi.fn((label: string, value: any): Content[] => [{ text: `${label}${value ?? ''}` }]), formatText: vi.fn((text: string, style?: any): Content => ({ text, style })), verticalSpacing: vi.fn().mockImplementation((size) => ({ margin: size })), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); vi.mock('./Adres', () => ({ @@ -25,38 +26,43 @@ vi.mock('./PodmiotDaneKontaktowe', () => ({ })); describe(generateCorrectedContent.name, () => { + const header = 'Treść korygowana'; + beforeEach(() => { vi.clearAllMocks(); }); it('should generate corrected content base values ', () => { const podmiot: Podmiot1K = {}; - const result: Content[] = generateCorrectedContent(podmiot); - expect((result[0] as any).some((c: any) => c.text === 'Treść korygowana')).toBe(true); + const result: Content[] = generateCorrectedContent(podmiot, header); + + expect((result[0] as any).some((c: any) => c.text === header)).toBe(true); }); it('should generate corrected content with prefixPodatnika ', () => { const podmiot: Podmiot1K = { PrefiksPodatnika: { _text: 'tekst' } }; - const result: Content[] = generateCorrectedContent(podmiot); - expect(result.length).equal(2); + const result: Content[] = generateCorrectedContent(podmiot, header); - expect((result[0] as any).some((c: any) => c.text === 'Treść korygowana')).toBe(true); + expect(result.length).equal(2); + expect((result[0] as any).some((c: any) => c.text === header)).toBe(true); expect((result[1] as any).some((c: any) => c.text.includes('Prefiks VAT: '))).toBe(true); expect((result[1] as any).some((c: any) => c.text.includes('[object Object]'))).toBe(true); }); it('should generate corrected content with id data ', () => { const podmiot: Podmiot1K = { DaneIdentyfikacyjne: { NIP: 'NIP' as FP, Nazwa: 'nazwa' as FP } }; - const result: Content[] = generateCorrectedContent(podmiot); + const result: Content[] = generateCorrectedContent(podmiot, header); + expect(result.length).equal(2); - expect((result[0] as any).some((c: any) => c.text === 'Treść korygowana')).toBe(true); + expect((result[0] as any).some((c: any) => c.text === header)).toBe(true); expect((result[1] as any).text.includes('mockDaneIdentyfikacyjne')).toBe(true); }); it('should generate corrected content with address ', () => { const podmiot: Podmiot1K = { Adres: { KodKraju: 'PL' as FP } }; - const result: any = generateCorrectedContent(podmiot); + const result: any = generateCorrectedContent(podmiot, header); + expect(result.length).equal(3); - expect((result[0] as any).some((c: any) => c.text === 'Treść korygowana')).toBe(true); + expect((result[0] as any).some((c: any) => c.text === header)).toBe(true); expect((result[1] as any).text.includes('Adres')).toBe(true); expect((result[2] as any).some((c: { text: string }) => c.text === 'mockAdres')).toBe(true); }); @@ -67,8 +73,9 @@ describe(generateCorrectedContent.name, () => { DaneIdentyfikacyjne: { NIP: '123' as FP, Nazwa: 'Firma' as FP }, Adres: { KodKraju: 'PL' as FP }, }; - const result: any = generateCorrectedContent(podmiot); - expect((result[0] as any).some((c: any) => c.text === 'Treść korygowana')).toBe(true); + const result: any = generateCorrectedContent(podmiot, header); + + expect((result[0] as any).some((c: any) => c.text === header)).toBe(true); expect((result[1] as any).some((c: any) => c.text.includes('Prefiks VAT: '))).toBe(true); expect((result[1] as any).some((c: any) => c.text.includes('[object Object]'))).toBe(true); expect((result[2] as any).text.includes('mockDaneIdentyfikacyjne')).toBe(true); diff --git a/src/lib-public/generators/FA2/Podmiot2.spec.ts b/src/lib-public/generators/FA2/Podmiot2.spec.ts index 5c4d7bb..9576880 100644 --- a/src/lib-public/generators/FA2/Podmiot2.spec.ts +++ b/src/lib-public/generators/FA2/Podmiot2.spec.ts @@ -15,6 +15,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ vi.mock('./Adres', async () => { const actual = await vi.importActual('./Adres'); + return { ...actual, generateAdres: vi.fn((adres: any): Content[] => [{ text: 'mockAddress' }]), @@ -23,6 +24,7 @@ vi.mock('./Adres', async () => { vi.mock('./PodmiotDaneIdentyfikacyjneTPodmiot2Dto', async () => { const actual = await vi.importActual('./PodmiotDaneIdentyfikacyjneTPodmiot2Dto'); + return { ...actual, generateDaneIdentyfikacyjneTPodmiot2Dto: vi.fn((data: any): Content[] => [ @@ -33,6 +35,7 @@ vi.mock('./PodmiotDaneIdentyfikacyjneTPodmiot2Dto', async () => { vi.mock('./PodmiotDaneKontaktowe', async () => { const actual = await vi.importActual('./PodmiotDaneKontaktowe'); + return { ...actual, generateDaneKontaktowe: vi.fn((data: any): Content[] => [{ text: 'mockDaneKontaktowe' }]), @@ -50,7 +53,7 @@ describe(generatePodmiot2.name, () => { expect(createHeader).toHaveBeenCalledWith('Nabywca'); expect(createLabelText).toHaveBeenCalledWith('Identyfikator nabywcy: ', 'ID123'); - expect(createLabelText).toHaveBeenCalledWith('NrEORI: ', 'EORI123'); + expect(createLabelText).toHaveBeenCalledWith('Numer EORI: ', 'EORI123'); expect(result[0]).toEqual({ text: 'Nabywca', style: 'header' }); }); @@ -98,6 +101,7 @@ describe(generatePodmiot2.name, () => { DaneKontaktowe: [{ Telefon: '123' }] as any, }; const result: Content = generatePodmiot2(podmiot as Podmiot2); + expect(result[0]).toEqual({ text: 'Nabywca', style: 'header' }); expect(result.some((c: any): boolean => c.text === 'mockDaneIdentyfikacyjne')).toBe(true); expect( diff --git a/src/lib-public/generators/FA2/Podmiot2.ts b/src/lib-public/generators/FA2/Podmiot2.ts index 9bfe316..49d52d3 100644 --- a/src/lib-public/generators/FA2/Podmiot2.ts +++ b/src/lib-public/generators/FA2/Podmiot2.ts @@ -12,7 +12,7 @@ export function generatePodmiot2(podmiot2: Podmiot2): Content[] { result.push( createLabelText('Identyfikator nabywcy: ', podmiot2.IDNabywcy), - createLabelText('NrEORI: ', podmiot2.NrEORI) + createLabelText('Numer EORI: ', podmiot2.NrEORI) ); if (podmiot2.DaneIdentyfikacyjne) { result.push( diff --git a/src/lib-public/generators/FA2/Podmiot2Podmiot2k.spec.ts b/src/lib-public/generators/FA2/Podmiot2Podmiot2k.spec.ts index 55bd781..0af2126 100644 --- a/src/lib-public/generators/FA2/Podmiot2Podmiot2k.spec.ts +++ b/src/lib-public/generators/FA2/Podmiot2Podmiot2k.spec.ts @@ -1,6 +1,8 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import type { Content } from 'pdfmake/interfaces'; import type { Podmiot2, Podmiot2K } from '../../types/fa2.types'; +import { generateAdres } from './Adres'; +import { generatePodmiot2Podmiot2K } from './Podmiot2Podmiot2k'; vi.mock('../../../shared/PDF-functions', () => ({ createHeader: vi.fn((text: string): Content[] => [{ text, style: 'header' }]), @@ -9,6 +11,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ getTable: vi.fn((data: any) => data || []), hasValue: vi.fn((value: any) => value !== undefined && value !== null), verticalSpacing: vi.fn((margin: number) => ({ margin })), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); vi.mock('./Adres', () => ({ @@ -25,10 +28,6 @@ vi.mock('./PodmiotDaneKontaktowe', () => ({ generateDaneKontaktowe: vi.fn((data: any): Content[] => [{ text: 'mockDaneKontaktowe' }]), })); -import { createHeader, createLabelText, formatText } from '../../../shared/PDF-functions'; -import { generateAdres } from './Adres'; -import { generatePodmiot2Podmiot2K } from './Podmiot2Podmiot2k'; - describe(generatePodmiot2Podmiot2K.name, () => { beforeEach(() => { vi.clearAllMocks(); @@ -52,10 +51,7 @@ describe(generatePodmiot2Podmiot2K.name, () => { expect(result[2]).toHaveProperty('columns'); expect(Array.isArray(result[2].columns[0])).toBe(true); - expect(Array.isArray(result[2].columns[1])).toBe(true); expect(result[2].columns[0].length).toBeGreaterThan(0); - expect(result[2].columns[1].length).toBeGreaterThan(0); - expect(result[3]).toEqual({ margin: 1 }); }); @@ -71,9 +67,8 @@ describe(generatePodmiot2Podmiot2K.name, () => { const podmiot2K: Podmiot2K = { IDNabywcy: 'ID123' } as any; const result = generatePodmiot2Podmiot2K(podmiot2, podmiot2K) as any; expect(Array.isArray(result[2].columns[0])).toBe(true); - expect(Array.isArray(result[2].columns[1])).toBe(true); + expect(Array.isArray(result[2].columns[1])).toBe(false); expect(result[2].columns[0].length).toBeGreaterThanOrEqual(0); - expect(result[2].columns[1].length).toBeGreaterThanOrEqual(0); }); it('adds vertical spacing at the end', () => { @@ -94,15 +89,12 @@ describe(generatePodmiot2Podmiot2K.name, () => { } as any; const podmiot2K: Podmiot2K = { IDNabywcy: 'ID123' } as any; const result = generatePodmiot2Podmiot2K(podmiot2, podmiot2K) as any; - expect(result.length).toBeGreaterThan(3); expect(result[0]).toEqual({ text: 'Nabywca', style: 'header' }); expect(result[2]).toHaveProperty('columns'); expect(Array.isArray(result[2].columns[0])).toBe(true); - expect(Array.isArray(result[2].columns[1])).toBe(true); expect(result[2].columns[0].length).toBeGreaterThanOrEqual(0); - expect(result[2].columns[1].length).toBeGreaterThanOrEqual(0); expect(result[result.length - 1]).toHaveProperty('margin'); }); diff --git a/src/lib-public/generators/FA2/Podmiot2Podmiot2k.ts b/src/lib-public/generators/FA2/Podmiot2Podmiot2k.ts index 4b72d33..c13eee8 100644 --- a/src/lib-public/generators/FA2/Podmiot2Podmiot2k.ts +++ b/src/lib-public/generators/FA2/Podmiot2Podmiot2k.ts @@ -3,6 +3,7 @@ import { createHeader, createLabelText, formatText, + generateColumns, getTable, hasValue, verticalSpacing, @@ -35,8 +36,8 @@ export function generatePodmiot2Podmiot2K(podmiot2: Podmiot2, podmiot2K: Podmiot columnGap: 20, }); } - firstColumn = generateCorrectedContent(podmiot2K); - secondColumn = generateCorrectedContent(podmiot2); + firstColumn = generateCorrectedContent(podmiot2K, 'Treść korygowana'); + secondColumn = generateCorrectedContent(podmiot2, 'Treść korygująca'); if (podmiot2.AdresKoresp) { secondColumn.push( formatText('Adres do korespondencji', [FormatTyp.Label, FormatTyp.LabelMargin]), @@ -45,10 +46,7 @@ export function generatePodmiot2Podmiot2K(podmiot2: Podmiot2, podmiot2K: Podmiot } if (firstColumn.length || secondColumn.length) { - result.push({ - columns: [firstColumn, secondColumn], - columnGap: 20, - }); + result.push(generateColumns([firstColumn, secondColumn])); } if (result.length) { result.push(verticalSpacing(1)); @@ -56,10 +54,10 @@ export function generatePodmiot2Podmiot2K(podmiot2: Podmiot2, podmiot2K: Podmiot return result; } -export function generateCorrectedContent(podmiot: Podmiot2 | Podmiot2K): Content[] { +export function generateCorrectedContent(podmiot: Podmiot2 | Podmiot2K, header: string): Content[] { const result: Content[] = []; - result.push(createHeader('Treść korygowana')); + result.push(createHeader(header)); if (hasValue(podmiot.IDNabywcy)) { result.push(createLabelText('Identyfikator nabywcy: ', podmiot.IDNabywcy)); diff --git a/src/lib-public/generators/FA2/Podmiot3.ts b/src/lib-public/generators/FA2/Podmiot3.ts index fcb532b..182857a 100644 --- a/src/lib-public/generators/FA2/Podmiot3.ts +++ b/src/lib-public/generators/FA2/Podmiot3.ts @@ -20,7 +20,7 @@ export function generatePodmiot3(podmiot: Podmiot3, index: number): Content[] { const column1: Content[] = [ ...createHeader(`Podmiot inny ${index + 1}`), createLabelText('Identyfikator nabywcy: ', podmiot.IDNabywcy), - createLabelText('NrEORI: ', podmiot.NrEORI), + createLabelText('Numer EORI: ', podmiot.NrEORI), ...generateDaneIdentyfikacyjneTPodmiot3Dto(podmiot.DaneIdentyfikacyjne), createLabelText('Rola: ', getRolaString(podmiot.Rola, 2)), createLabelText('Rola inna: ', podmiot.OpisRoli), diff --git a/src/lib-public/generators/FA2/PodmiotDaneKontaktowe.spec.ts b/src/lib-public/generators/FA2/PodmiotDaneKontaktowe.spec.ts index 39c0aa1..1f1ec01 100644 --- a/src/lib-public/generators/FA2/PodmiotDaneKontaktowe.spec.ts +++ b/src/lib-public/generators/FA2/PodmiotDaneKontaktowe.spec.ts @@ -21,11 +21,11 @@ describe(generateDaneKontaktowe.name, () => { it('returns mapped Content array when daneKontaktowe is provided', () => { const result = generateDaneKontaktowe(mockData); expect(getTable).toHaveBeenCalledWith(mockData); - expect(createLabelText).toHaveBeenCalledWith('Email: ', mockData[0].Email); + expect(createLabelText).toHaveBeenCalledWith('E-mail: ', mockData[0].Email); expect(createLabelText).toHaveBeenCalledWith('Tel.: ', mockData[0].Telefon); expect(Array.isArray(result)).toBe(true); expect(result?.length).toBe(2); - expect(result?.[0]).toEqual([{ text: 'Email: test@example.com' }, { text: 'Tel.: 123456789' }]); + expect(result?.[0]).toEqual([{ text: 'E-mail: test@example.com' }, { text: 'Tel.: 123456789' }]); }); it('returns undefined when getTable returns undefined', () => { diff --git a/src/lib-public/generators/FA2/PodmiotDaneKontaktowe.ts b/src/lib-public/generators/FA2/PodmiotDaneKontaktowe.ts index 148719c..8ecee4e 100644 --- a/src/lib-public/generators/FA2/PodmiotDaneKontaktowe.ts +++ b/src/lib-public/generators/FA2/PodmiotDaneKontaktowe.ts @@ -5,7 +5,7 @@ import { Podmiot1DaneKontaktowe } from '../../types/fa2.types'; export function generateDaneKontaktowe(daneKontaktowe: Podmiot1DaneKontaktowe[]): Content[] { return getTable(daneKontaktowe)?.map((daneKontaktowe) => { return [ - createLabelText('Email: ', daneKontaktowe.Email), + createLabelText('E-mail: ', daneKontaktowe.Email), createLabelText('Tel.: ', daneKontaktowe.Telefon), ]; }); diff --git a/src/lib-public/generators/FA2/Podmioty.spec.ts b/src/lib-public/generators/FA2/Podmioty.spec.ts index 23b6a0a..601f9ea 100644 --- a/src/lib-public/generators/FA2/Podmioty.spec.ts +++ b/src/lib-public/generators/FA2/Podmioty.spec.ts @@ -14,6 +14,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ createSection: vi.fn((content: any, flag: boolean) => ({ content, flag })), getTable: vi.fn((data: any) => data || []), getValue: vi.fn((val: any) => val?._text ?? val), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); vi.mock('./Podmiot1', () => ({ diff --git a/src/lib-public/generators/FA2/Podmioty.ts b/src/lib-public/generators/FA2/Podmioty.ts index bc5fe35..de28971 100644 --- a/src/lib-public/generators/FA2/Podmioty.ts +++ b/src/lib-public/generators/FA2/Podmioty.ts @@ -1,5 +1,5 @@ import { Content } from 'pdfmake/interfaces'; -import { createSection, getTable, getValue } from '../../../shared/PDF-functions'; +import { createSection, generateColumns, getTable, getValue } from '../../../shared/PDF-functions'; import { Faktura, Podmiot2K as Podmiot2Kfa2, Podmiot3 } from '../../types/fa2.types'; import { Podmiot2K as Podmiot2Kfa1 } from '../../types/fa1.types'; import { Podmiot3Podmiot2KDto } from '../../types/fa2-additional-types'; @@ -32,10 +32,10 @@ export function generatePodmioty(invoice: Faktura): Content[] { } } else { result.push([ - { - columns: [generatePodmiot1(invoice.Podmiot1!), generatePodmiot2(invoice.Podmiot2!)], + generateColumns([generatePodmiot1(invoice.Podmiot1!), generatePodmiot2(invoice.Podmiot2!)], { margin: [0, 0, 0, 8], - }, + columnGap: 20, + }), ]); } diff --git a/src/lib-public/generators/FA2/RachunekBankowy.spec.ts b/src/lib-public/generators/FA2/RachunekBankowy.spec.ts new file mode 100644 index 0000000..fa2c629 --- /dev/null +++ b/src/lib-public/generators/FA2/RachunekBankowy.spec.ts @@ -0,0 +1,259 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { generujRachunekBankowy } from './RachunekBankowy'; +import * as PDFFunctions from '../../../shared/PDF-functions'; +import FormatTyp from '../../../shared/enums/common.enum'; +import { FP } from '../../types/fa2.types'; +import * as CommonFunctions from '../../../shared/generators/common/functions'; +import { makeBreakable } from '../../../shared/PDF-functions'; + +vi.mock('../../../shared/PDF-functions', () => ({ + createHeader: vi.fn(), + createSection: vi.fn(), + formatText: vi.fn(), + makeBreakable: vi.fn(), + getValue: vi.fn((val) => (val && val._text ? val._text : '')), + hasValue: vi.fn((val) => Boolean(val && val._text)), +})); + +vi.mock('../../../shared/generators/common/functions', () => ({ + getTypRachunkowWlasnych: vi.fn(), +})); + +describe(generujRachunekBankowy.name, () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + const mockAccount: Record = { + NrRB: { _text: '12345678901234567890123456' }, + SWIFT: { _text: 'BPKOPLPW' }, + RachunekWlasnyBanku: { _text: '1' }, + NazwaBanku: { _text: 'PKO Bank Polski' }, + OpisRachunku: { _text: 'Rachunek główny' }, + }; + + beforeEach(() => { + vi.mocked(PDFFunctions.createHeader).mockReturnValue(['header'] as any); + vi.mocked(PDFFunctions.createSection).mockReturnValue('section' as any); + vi.mocked(PDFFunctions.formatText).mockReturnValue('formatted' as any); + vi.mocked(CommonFunctions.getTypRachunkowWlasnych).mockReturnValue('Tak'); + }); + + describe('when accounts is undefined or empty', () => { + it('should return empty array when accounts is undefined', () => { + const result = generujRachunekBankowy(undefined, 'Rachunek bankowy'); + + expect(result).toEqual([]); + }); + + it('should return empty array when accounts is empty array', () => { + const result = generujRachunekBankowy([], 'Rachunek bankowy'); + + expect(result).toEqual([]); + }); + }); + + describe('when accounts exist', () => { + it('should call createHeader with provided title', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Rachunek bankowy ', [0, 12, 0, 8]); + }); + + it('should call createHeader with empty string when title is not provided', () => { + generujRachunekBankowy([mockAccount]); + + expect(PDFFunctions.createHeader).toHaveBeenCalledWith('', [0, 12, 0, 8]); + }); + + it('should call createSection and return result', () => { + const mockSection = 'section'; + + vi.mocked(PDFFunctions.createSection).mockReturnValue(mockSection as any); + + const result = generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.createSection).toHaveBeenCalledWith(expect.any(Array), false); + expect(result).toEqual(mockSection); + }); + + it('should format "Pełny numer rachunku" field', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Pełny numer rachunku', FormatTyp.GrayBoldTitle); + expect(PDFFunctions.formatText).toHaveBeenCalledWith(mockAccount.NrRB?._text, FormatTyp.Default); + }); + + it('should format "Kod SWIFT" field', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Kod SWIFT', FormatTyp.GrayBoldTitle); + expect(PDFFunctions.formatText).toHaveBeenCalledWith(mockAccount.SWIFT?._text, FormatTyp.Default); + }); + + it('should format "Rachunek własny banku" field', () => { + vi.mocked(CommonFunctions.getTypRachunkowWlasnych).mockReturnValue('Tak'); + + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Rachunek własny banku', FormatTyp.GrayBoldTitle); + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledWith(mockAccount.RachunekWlasnyBanku); + expect(PDFFunctions.formatText).toHaveBeenCalledWith(makeBreakable('Tak', 20), FormatTyp.Default); + }); + + it('should format "Nazwa banku" field', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith( + makeBreakable(mockAccount.NazwaBanku?._text), + FormatTyp.Default + ); + }); + + it('should format "Opis rachunku" field', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Opis rachunku', FormatTyp.GrayBoldTitle); + expect(PDFFunctions.formatText).toHaveBeenCalledWith( + makeBreakable(mockAccount.OpisRachunku?._text), + FormatTyp.Default + ); + }); + + it('should create table structure with correct widths', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent).toHaveProperty('table'); + expect(tableContent.table).toHaveProperty('widths', ['*', 'auto']); + }); + + it('should create table structure with unbreakable property', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent).toHaveProperty('unbreakable', true); + }); + + it('should create table with correct layout', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent).toHaveProperty('layout'); + expect(tableContent.layout).toHaveProperty('hLineWidth'); + expect(tableContent.layout).toHaveProperty('hLineColor'); + expect(tableContent.layout).toHaveProperty('vLineWidth'); + expect(tableContent.layout).toHaveProperty('vLineColor'); + }); + + it('should create table with correct line colors', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent.layout.hLineColor()).toBe('#BABABA'); + expect(tableContent.layout.vLineColor()).toBe('#BABABA'); + }); + + it('should create table with correct line widths', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent.layout.hLineWidth()).toBe(1); + expect(tableContent.layout.vLineWidth()).toBe(1); + }); + + it('should handle account with undefined fields', () => { + const accountWithUndefined: Record = { + NrRB: { _text: undefined }, + SWIFT: { _text: undefined }, + RachunekWlasnyBanku: { _text: undefined }, + NazwaBanku: { _text: undefined }, + OpisRachunku: { _text: undefined }, + }; + + generujRachunekBankowy([accountWithUndefined], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith(undefined, FormatTyp.Default); + }); + }); + + describe('when multiple accounts exist', () => { + it('should create multiple tables for multiple accounts', () => { + const account2: Record = { + NrRB: { _text: '98765432109876543210987654' }, + SWIFT: { _text: 'PKOPPLPW' }, + RachunekWlasnyBanku: { _text: '0' }, + NazwaBanku: { _text: 'mBank' }, + OpisRachunku: { _text: 'Rachunek pomocniczy' }, + }; + + generujRachunekBankowy([mockAccount, account2], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + + expect(sectionCall.length).toBe(2); + }); + + it('should call getTypRachunkowWlasnych for each account', () => { + const account2: Record = { + NrRB: { _text: '98765432109876543210987654' }, + SWIFT: { _text: 'PKOPPLPW' }, + RachunekWlasnyBanku: { _text: '0' }, + NazwaBanku: { _text: 'mBank' }, + OpisRachunku: { _text: 'Rachunek pomocniczy' }, + }; + + generujRachunekBankowy([mockAccount, account2], 'Rachunek bankowy'); + + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledTimes(2); + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledWith(mockAccount.RachunekWlasnyBanku); + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledWith(account2.RachunekWlasnyBanku); + }); + + it('should format all fields for all accounts', () => { + const account2: Record = { + NrRB: { _text: '98765432109876543210987654' }, + SWIFT: { _text: 'PKOPPLPW' }, + RachunekWlasnyBanku: { _text: '0' }, + NazwaBanku: { _text: 'mBank' }, + OpisRachunku: { _text: 'Rachunek pomocniczy' }, + }; + + generujRachunekBankowy([mockAccount, account2], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith(mockAccount.NrRB?._text, FormatTyp.Default); + expect(PDFFunctions.formatText).toHaveBeenCalledWith(account2.NrRB?._text, FormatTyp.Default); + }); + }); + + describe('table structure', () => { + it('should create table with 5 rows', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent.table.body.length).toBe(5); + }); + + it('should include header in result array', () => { + vi.mocked(PDFFunctions.createHeader).mockReturnValue(['header-content'] as any); + + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + + expect(sectionCall[0][0]).toBe('header-content'); + }); + }); +}); diff --git a/src/lib-public/generators/FA2/RachunekBankowy.ts b/src/lib-public/generators/FA2/RachunekBankowy.ts index c24217c..840e0d9 100644 --- a/src/lib-public/generators/FA2/RachunekBankowy.ts +++ b/src/lib-public/generators/FA2/RachunekBankowy.ts @@ -1,5 +1,12 @@ import { Content, ContentTable } from 'pdfmake/interfaces'; -import { createHeader, createSection, formatText } from '../../../shared/PDF-functions'; +import { + createHeader, + createSection, + formatText, + getValue, + hasValue, + makeBreakable, +} from '../../../shared/PDF-functions'; import FormatTyp from '../../../shared/enums/common.enum'; import { RachunekBankowy } from '../../types/fa2.types'; import { getTypRachunkowWlasnych } from '../../../shared/generators/common/functions'; @@ -25,23 +32,33 @@ export const generujRachunekBankowy: (accounts?: Record[], title?: s table.push([ formatText('Pełny numer rachunku', FormatTyp.GrayBoldTitle), - formatText(account.NrRB?._text, FormatTyp.Default), + formatText(getValue(account.NrRB), FormatTyp.Default), ]); table.push([ formatText('Kod SWIFT', FormatTyp.GrayBoldTitle), - formatText(account.SWIFT?._text, FormatTyp.Default), + formatText(getValue(account.SWIFT), FormatTyp.Default), ]); table.push([ formatText('Rachunek własny banku', FormatTyp.GrayBoldTitle), - formatText(getTypRachunkowWlasnych(account.RachunekWlasnyBanku), FormatTyp.Default), + formatText(makeBreakable(getTypRachunkowWlasnych(account.RachunekWlasnyBanku), 20), FormatTyp.Default), ]); table.push([ formatText('Nazwa banku', FormatTyp.GrayBoldTitle), - formatText(account.NazwaBanku?._text, FormatTyp.Default), + formatText( + hasValue(account.NazwaBanku) + ? makeBreakable(getValue(account.NazwaBanku), 20) + : getValue(account.NazwaBanku), + FormatTyp.Default + ), ]); table.push([ formatText('Opis rachunku', FormatTyp.GrayBoldTitle), - formatText(account.OpisRachunku?._text, FormatTyp.Default), + formatText( + hasValue(account.OpisRachunku) + ? makeBreakable(getValue(account.OpisRachunku), 20) + : getValue(account.OpisRachunku), + FormatTyp.Default + ), ]); result.push([ ...base, diff --git a/src/lib-public/generators/FA3/Adnotacje.spec.ts b/src/lib-public/generators/FA3/Adnotacje.spec.ts index 1247e32..fbb2755 100644 --- a/src/lib-public/generators/FA3/Adnotacje.spec.ts +++ b/src/lib-public/generators/FA3/Adnotacje.spec.ts @@ -1,4 +1,6 @@ -import { describe, it, expect, vi, beforeEach, test } from 'vitest'; +import { beforeEach, describe, expect, it, test, vi } from 'vitest'; +import { createHeader, createLabelText, formatText, getTable } from '../../../shared/PDF-functions'; +import { generateAdnotacje, generateDostawy } from './Adnotacje'; vi.mock('../../../shared/PDF-functions', () => ({ createHeader: vi.fn((text: string) => ({ text, style: 'header' })), @@ -7,11 +9,9 @@ vi.mock('../../../shared/PDF-functions', () => ({ getTable: vi.fn(() => []), hasValue: vi.fn((v) => !!v?._text), verticalSpacing: vi.fn((n: number) => ({ text: `space-${n}` })), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); -import { createHeader, createLabelText, getTable, formatText } from '../../../shared/PDF-functions'; -import { generateAdnotacje, generateDostawy } from './Adnotacje'; - describe(generateAdnotacje.name, () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/src/lib-public/generators/FA3/Adnotacje.ts b/src/lib-public/generators/FA3/Adnotacje.ts index 6ad421d..92ce9f5 100644 --- a/src/lib-public/generators/FA3/Adnotacje.ts +++ b/src/lib-public/generators/FA3/Adnotacje.ts @@ -3,6 +3,7 @@ import { createHeader, createLabelText, formatText, + generateColumns, getTable, hasValue, verticalSpacing, @@ -130,7 +131,7 @@ export function generateAdnotacje(adnotacje?: Adnotacje): Content[] { addToColumn(firstColumn, secondColumn, { text: 'Samofakturowanie' }); } if (firstColumn.length || secondColumn.length) { - result.push({ columns: [firstColumn, secondColumn], columnGap: 20 }); + result.push(generateColumns([firstColumn, secondColumn])); } if (result.length) { diff --git a/src/lib-public/generators/FA3/DodatkoweInformacje.spec.ts b/src/lib-public/generators/FA3/DodatkoweInformacje.spec.ts index a86d1aa..c93cd85 100644 --- a/src/lib-public/generators/FA3/DodatkoweInformacje.spec.ts +++ b/src/lib-public/generators/FA3/DodatkoweInformacje.spec.ts @@ -76,4 +76,17 @@ describe(generateDodatkoweInformacje.name, () => { expect(createSection).toHaveBeenCalled(); expect(result.length).toBeGreaterThan(0); }); + + it('poprawnie dodaje sekcję FP', () => { + const faVat = { + FP: { _text: '1' }, + }; + const result = generateDodatkoweInformacje(faVat as any); + + expect(formatText).toHaveBeenCalledWith( + '- Faktura, o której mowa w art. 109 ust. 3d ustawy' + ); + expect(createSection).toHaveBeenCalled(); + expect(result.length).toBeGreaterThan(0); + }); }); diff --git a/src/lib-public/generators/FA3/DodatkoweInformacje.ts b/src/lib-public/generators/FA3/DodatkoweInformacje.ts index 81df2d8..826ded7 100644 --- a/src/lib-public/generators/FA3/DodatkoweInformacje.ts +++ b/src/lib-public/generators/FA3/DodatkoweInformacje.ts @@ -13,15 +13,20 @@ import { DodatkowyOpi, Fa } from '../../types/fa3.types'; import FormatTyp from '../../../shared/enums/common.enum'; export function generateDodatkoweInformacje(faVat: Fa): Content[] { - const tpLabel1: Content[] = []; - const tpLabel2: Content[] = []; + const tpLabel: Content[] = []; if (getValue(faVat.TP) === '1') { - tpLabel1.push( + tpLabel.push( formatText('- Istniejące powiązania między nabywcą a dokonującym dostawy towarów lub usługodawcą') ); - tpLabel2.push(formatText('- Faktura, o której mowa w art. 109 ust. 3d ustawy')); } + + const fpLabel: Content[] = []; + + if (getValue(faVat.FP) === '1') { + fpLabel.push(formatText('- Faktura, o której mowa w art. 109 ust. 3d ustawy')); + } + const zwrotAkcyzyLabel: Content[] = []; if (getValue(faVat.ZwrotAkcyzy) === '1') { @@ -32,7 +37,7 @@ export function generateDodatkoweInformacje(faVat: Fa): Content[] { ); } - const labels = [tpLabel1, tpLabel2, zwrotAkcyzyLabel].filter((el) => el.length > 0); + const labels = [tpLabel, fpLabel, zwrotAkcyzyLabel].filter((el) => el.length > 0); const table: Content[] = [ ...createHeader('Dodatkowe informacje'), ...labels, diff --git a/src/lib-public/generators/FA3/Platnosc.ts b/src/lib-public/generators/FA3/Platnosc.ts index 90f7fb4..71e63ed 100644 --- a/src/lib-public/generators/FA3/Platnosc.ts +++ b/src/lib-public/generators/FA3/Platnosc.ts @@ -80,7 +80,9 @@ export function generatePlatnosc(platnosc: Platnosc | undefined): Content { const tableZaplataCzesciowa = getContentTable<(typeof zaplataCzesciowa)[0]>( zaplataCzesciowaNaglowek, zaplataCzesciowa, - '*' + '*', + undefined, + 20 ); const terminPatnosciContent = terminPlatnosci.map((platnosc) => { if (!terminPlatnosci.some((termin) => termin.TerminOpis)) { @@ -98,7 +100,9 @@ export function generatePlatnosc(platnosc: Platnosc | undefined): Content { const tableTerminPlatnosci = getContentTable<(typeof terminPlatnosci)[0]>( zaplataCzesciowaHeader, terminPatnosciContent, - '*' + '*', + undefined, + 20 ); if (zaplataCzesciowa.length > 0 && terminPlatnosci.length > 0) { @@ -125,7 +129,7 @@ export function generatePlatnosc(platnosc: Platnosc | undefined): Content { } as ContentText); } if (platnosc.IPKSeF?._text) { - createLabelText('Identyfikator płatności Krajowego Systemu e-Faktur: ', platnosc.IPKSeF); + table.push(createLabelText('Identyfikator płatności Krajowego Systemu e-Faktur: ', platnosc.IPKSeF)); } table.push( diff --git a/src/lib-public/generators/FA3/Podmiot1.spec.ts b/src/lib-public/generators/FA3/Podmiot1.spec.ts index f9181cd..6f50afd 100644 --- a/src/lib-public/generators/FA3/Podmiot1.spec.ts +++ b/src/lib-public/generators/FA3/Podmiot1.spec.ts @@ -11,6 +11,8 @@ vi.mock('../../../shared/PDF-functions', () => ({ createHeader: vi.fn((text: string): Content[] => [{ text, style: 'header' }]), createLabelText: vi.fn((label: string, value: any): Content[] => [{ text: `${label}${value ?? ''}` }]), formatText: vi.fn((text: string, style?: any): Content => ({ text, style })), + getValue: vi.fn((val) => val?._text || ''), + hasValue: vi.fn((val) => Boolean(val && val._text)), })); vi.mock('./Adres', () => ({ @@ -40,7 +42,7 @@ describe(generatePodmiot1.name, () => { const result = generatePodmiot1(podmiot as Podmiot1); expect(createHeader).toHaveBeenCalledWith('Sprzedawca'); - expect(createLabelText).toHaveBeenCalledWith('NrEORI: ', 'EORI123'); + expect(createLabelText).toHaveBeenCalledWith('Numer EORI: ', 'EORI123'); expect(createLabelText).toHaveBeenCalledWith('Prefiks VAT: ', 'PL'); expect((result as any[]).some((c) => c?.[0]?.text.includes('EORI123'))).toBe(true); }); @@ -72,25 +74,23 @@ describe(generatePodmiot1.name, () => { expect(formatText).toHaveBeenCalledWith('Adres do korespondencji', ['Label', 'LabelMargin']); }); - it('generates contact data and taxpayer status', () => { + it('generates contact data', () => { const podmiot: Partial = { DaneKontaktowe: [{ Telefon: { _text: '123' } }], - StatusInfoPodatnika: { _text: 'active' }, }; const result = generatePodmiot1(podmiot as Podmiot1); expect(generateDaneKontaktowe).toHaveBeenCalledWith([{ Telefon: { _text: '123' } }]); - expect(createLabelText).toHaveBeenCalledWith('Status podatnika: ', { _text: 'active' }); expect(result.some((c) => (c as any).text === 'mockDaneKontaktowe')).toBe(true); }); - it('generates only taxpayer status if no contact data', () => { + it('generates taxpayer status', () => { const podmiot: Partial = { - StatusInfoPodatnika: { _text: 'inactive' }, + StatusInfoPodatnika: { _text: '1' }, }; const result = generatePodmiot1(podmiot as Podmiot1); - expect(generateDaneKontaktowe).not.toHaveBeenCalled(); - expect(createLabelText).toHaveBeenCalledWith('Status podatnika: ', { _text: 'inactive' }); + expect(createLabelText).toHaveBeenCalledWith('Status podatnika: ', 'Stan likwidacji'); + expect(result.some((c) => (c as any).text === 'mockDaneKontaktowe')).toBe(false); }); }); diff --git a/src/lib-public/generators/FA3/Podmiot1.ts b/src/lib-public/generators/FA3/Podmiot1.ts index 238535a..5041dfb 100644 --- a/src/lib-public/generators/FA3/Podmiot1.ts +++ b/src/lib-public/generators/FA3/Podmiot1.ts @@ -1,16 +1,17 @@ import { Content } from 'pdfmake/interfaces'; -import { createHeader, createLabelText, formatText } from '../../../shared/PDF-functions'; +import { createHeader, createLabelText, formatText, getValue, hasValue } from '../../../shared/PDF-functions'; import FormatTyp from '../../../shared/enums/common.enum'; import { Podmiot1 } from '../../types/fa3.types'; import { generateAdres } from './Adres'; import { generateDaneIdentyfikacyjneTPodmiot1Dto } from './PodmiotDaneIdentyfikacyjneTPodmiot1Dto'; import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe'; +import { TAXPAYER_STATUS } from '../../../shared/consts/const'; export function generatePodmiot1(podmiot1: Podmiot1): Content[] { const result: Content[] = createHeader('Sprzedawca'); result.push( - createLabelText('NrEORI: ', podmiot1.NrEORI), + createLabelText('Numer EORI: ', podmiot1.NrEORI), createLabelText('Prefiks VAT: ', podmiot1.PrefiksPodatnika) ); if (podmiot1.DaneIdentyfikacyjne) { @@ -31,10 +32,11 @@ export function generatePodmiot1(podmiot1: Podmiot1): Content[] { formatText('Dane kontaktowe', [FormatTyp.Label, FormatTyp.LabelMargin]), ...generateDaneKontaktowe(podmiot1.DaneKontaktowe) ); + } + if (hasValue(podmiot1.StatusInfoPodatnika)) { + const statusInfo: string = TAXPAYER_STATUS[getValue(podmiot1.StatusInfoPodatnika)!]; - result.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika)); - } else if (podmiot1.StatusInfoPodatnika) { - result.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika)); + result.push(createLabelText('Status podatnika: ', statusInfo)); } return result; } diff --git a/src/lib-public/generators/FA3/Podmiot1Podmiot1K.spec.ts b/src/lib-public/generators/FA3/Podmiot1Podmiot1K.spec.ts index 0b39648..44a476b 100644 --- a/src/lib-public/generators/FA3/Podmiot1Podmiot1K.spec.ts +++ b/src/lib-public/generators/FA3/Podmiot1Podmiot1K.spec.ts @@ -10,6 +10,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ getTable: vi.fn((data: any) => data || []), formatText: vi.fn((text: string, style?: any): Content => ({ text, style })), verticalSpacing: vi.fn((margin: number) => ({ margin })), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); vi.mock('./Adres', () => ({ @@ -60,9 +61,7 @@ describe(generatePodmiot1Podmiot1K.name, () => { expect(result[2]).toHaveProperty('columns'); expect(Array.isArray(result[2].columns[0])).toBe(true); - expect(Array.isArray(result[2].columns[1])).toBe(true); expect(result[2].columns[0].length).toBeGreaterThan(0); - expect(result[2].columns[1].length).toBeGreaterThan(0); expect(result[3]).toEqual({ margin: 1 }); }); @@ -87,13 +86,9 @@ describe(generatePodmiot1Podmiot1K.name, () => { expect(result.length).toBe(4); expect(result[0]).toEqual({ text: 'Sprzedawca', style: 'header' }); - expect(result[1].columns[0]).toBeInstanceOf(Array); expect(result[1].columns[1]).toBeInstanceOf(Array); - expect(result[2].columns[0]).toBeInstanceOf(Array); - expect(result[2].columns[1]).toBeInstanceOf(Array); - expect(result[3]).toEqual({ margin: 1 }); }); }); diff --git a/src/lib-public/generators/FA3/Podmiot1Podmiot1K.ts b/src/lib-public/generators/FA3/Podmiot1Podmiot1K.ts index 328eaca..86748ae 100644 --- a/src/lib-public/generators/FA3/Podmiot1Podmiot1K.ts +++ b/src/lib-public/generators/FA3/Podmiot1Podmiot1K.ts @@ -3,6 +3,7 @@ import { createHeader, createLabelText, formatText, + generateColumns, getTable, verticalSpacing, } from '../../../shared/PDF-functions'; @@ -39,8 +40,8 @@ export function generatePodmiot1Podmiot1K(podmiot1: Podmiot1, podmiot1K: Podmiot columnGap: 20, }); } - firstColumn = generateCorrectedContent(podmiot1K); - secondColumn = generateCorrectedContent(podmiot1); + firstColumn = generateCorrectedContent(podmiot1K, 'Treść korygowana'); + secondColumn = generateCorrectedContent(podmiot1, 'Treść korygująca'); if (podmiot1.AdresKoresp) { secondColumn.push( @@ -49,10 +50,7 @@ export function generatePodmiot1Podmiot1K(podmiot1: Podmiot1, podmiot1K: Podmiot ); } if (firstColumn.length || secondColumn.length) { - result.push({ - columns: [firstColumn, secondColumn], - columnGap: 20, - }); + result.push(generateColumns([firstColumn, secondColumn])); } if (result.length) { result.push(verticalSpacing(1)); @@ -60,10 +58,10 @@ export function generatePodmiot1Podmiot1K(podmiot1: Podmiot1, podmiot1K: Podmiot return result; } -export function generateCorrectedContent(podmiot: Podmiot1 | Podmiot1K): Content[] { +export function generateCorrectedContent(podmiot: Podmiot1 | Podmiot1K, header: string): Content[] { const result: Content[] = []; - result.push(createHeader('Treść korygowana')); + result.push(createHeader(header)); if (podmiot.PrefiksPodatnika?._text) { result.push(createLabelText('Prefiks VAT: ', podmiot.PrefiksPodatnika)); diff --git a/src/lib-public/generators/FA3/Podmiot2.spec.ts b/src/lib-public/generators/FA3/Podmiot2.spec.ts index ac12078..01575a8 100644 --- a/src/lib-public/generators/FA3/Podmiot2.spec.ts +++ b/src/lib-public/generators/FA3/Podmiot2.spec.ts @@ -18,6 +18,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ vi.mock('./Adres', async () => { const actual = await vi.importActual('./Adres'); + return { ...actual, generateAdres: vi.fn((): Content[] => [{ text: 'mockAddress' } as Content]), @@ -26,6 +27,7 @@ vi.mock('./Adres', async () => { vi.mock('./PodmiotDaneIdentyfikacyjneTPodmiot2Dto', async () => { const actual = await vi.importActual('./PodmiotDaneIdentyfikacyjneTPodmiot2Dto'); + return { ...actual, generateDaneIdentyfikacyjneTPodmiot2Dto: vi.fn((): Content[] => [ @@ -36,6 +38,7 @@ vi.mock('./PodmiotDaneIdentyfikacyjneTPodmiot2Dto', async () => { vi.mock('./PodmiotDaneKontaktowe', async () => { const actual = await vi.importActual('./PodmiotDaneKontaktowe'); + return { ...actual, generateDaneKontaktowe: vi.fn((): Content[] => [{ text: 'mockDaneKontaktowe' } as Content]), @@ -53,7 +56,7 @@ describe(generatePodmiot2.name, () => { expect(createHeader).toHaveBeenCalledWith('Nabywca'); expect(createLabelText).toHaveBeenCalledWith('Identyfikator nabywcy: ', 'ID123'); - expect(createLabelText).toHaveBeenCalledWith('NrEORI: ', 'EORI123'); + expect(createLabelText).toHaveBeenCalledWith('Numer EORI: ', 'EORI123'); expect(result[0]).toEqual({ text: 'Nabywca', style: 'header' }); }); @@ -110,8 +113,8 @@ describe(generatePodmiot2.name, () => { const addressCount = result.filter((c: any) => c.text === 'mockAddress').length; const fifthElementLength = Array.isArray(result[5]) ? result[5].length : 0; - expect(addressCount + fifthElementLength).toBe(2); + expect(addressCount + fifthElementLength).toBe(2); expect(result.some((c: any) => c.text === 'mockDaneKontaktowe')).toBe(true); expect(createLabelText).toHaveBeenCalledWith('Numer klienta: ', 'CL123'); }); diff --git a/src/lib-public/generators/FA3/Podmiot2.ts b/src/lib-public/generators/FA3/Podmiot2.ts index b12f955..0703532 100644 --- a/src/lib-public/generators/FA3/Podmiot2.ts +++ b/src/lib-public/generators/FA3/Podmiot2.ts @@ -12,7 +12,7 @@ export function generatePodmiot2(podmiot2: Podmiot2): Content[] { result.push( createLabelText('Identyfikator nabywcy: ', podmiot2.IDNabywcy), - createLabelText('NrEORI: ', podmiot2.NrEORI) + createLabelText('Numer EORI: ', podmiot2.NrEORI) ); if (podmiot2.DaneIdentyfikacyjne) { result.push( diff --git a/src/lib-public/generators/FA3/Podmiot2Podmiot2k.spec.ts b/src/lib-public/generators/FA3/Podmiot2Podmiot2k.spec.ts index 6f4e491..2a2d0a5 100644 --- a/src/lib-public/generators/FA3/Podmiot2Podmiot2k.spec.ts +++ b/src/lib-public/generators/FA3/Podmiot2Podmiot2k.spec.ts @@ -12,6 +12,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ getTable: vi.fn((data: any) => data || []), hasValue: vi.fn((value: any) => value !== undefined && value !== null), verticalSpacing: vi.fn((margin: number) => ({ margin })), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); vi.mock('./Adres', () => ({ @@ -51,9 +52,8 @@ describe(generatePodmiot2Podmiot2K.name, () => { expect(result[2]).toHaveProperty('columns'); expect(Array.isArray(result[2].columns[0])).toBe(true); - expect(Array.isArray(result[2].columns[1])).toBe(true); + expect(Array.isArray(result[2].columns[1])).toBe(false); expect(result[2].columns[0].length).toBeGreaterThan(0); - expect(result[2].columns[1].length).toBeGreaterThan(0); expect(result[3]).toEqual({ margin: 1 }); }); @@ -71,10 +71,9 @@ describe(generatePodmiot2Podmiot2K.name, () => { const podmiot2: Podmiot2 = { NrEORI: 'EORI123' } as any; const podmiot2K: Podmiot2K = { IDNabywcy: 'ID123' } as any; const result = generatePodmiot2Podmiot2K(podmiot2, podmiot2K) as any; + expect(Array.isArray(result[2].columns[0])).toBe(true); - expect(Array.isArray(result[2].columns[1])).toBe(true); expect(result[2].columns[0].length).toBeGreaterThanOrEqual(0); - expect(result[2].columns[1].length).toBeGreaterThanOrEqual(0); }); it('adds vertical spacing at the end', () => { @@ -101,10 +100,8 @@ describe(generatePodmiot2Podmiot2K.name, () => { expect(result[2]).toHaveProperty('columns'); expect(Array.isArray(result[2].columns[0])).toBe(true); - expect(Array.isArray(result[2].columns[1])).toBe(true); + expect(Array.isArray(result[2].columns[1])).toBe(false); expect(result[2].columns[0].length).toBeGreaterThanOrEqual(0); - expect(result[2].columns[1].length).toBeGreaterThanOrEqual(0); - expect(result[result.length - 1]).toHaveProperty('margin'); }); }); diff --git a/src/lib-public/generators/FA3/Podmiot2Podmiot2k.ts b/src/lib-public/generators/FA3/Podmiot2Podmiot2k.ts index b69f7b2..49c58bf 100644 --- a/src/lib-public/generators/FA3/Podmiot2Podmiot2k.ts +++ b/src/lib-public/generators/FA3/Podmiot2Podmiot2k.ts @@ -3,6 +3,7 @@ import { createHeader, createLabelText, formatText, + generateColumns, getTable, verticalSpacing, } from '../../../shared/PDF-functions'; @@ -37,8 +38,9 @@ export function generatePodmiot2Podmiot2K(podmiot2: Podmiot2, podmiot2K: Podmiot columnGap: 20, }); } - firstColumn = generateCorrectedContent(podmiot2K); - secondColumn = generateCorrectedContent(podmiot2); + firstColumn = generateCorrectedContent(podmiot2K, 'Treść korygowana'); + secondColumn = generateCorrectedContent(podmiot2, 'Treść korygująca'); + if (podmiot2.AdresKoresp) { secondColumn.push( formatText('Adres do korespondencji', [FormatTyp.Label, FormatTyp.LabelMargin]), @@ -47,10 +49,7 @@ export function generatePodmiot2Podmiot2K(podmiot2: Podmiot2, podmiot2K: Podmiot } if (firstColumn.length || secondColumn.length) { - result.push({ - columns: [firstColumn, secondColumn], - columnGap: 20, - }); + result.push(generateColumns([firstColumn, secondColumn])); } if (result.length) { result.push(verticalSpacing(1)); diff --git a/src/lib-public/generators/FA3/Podmiot3.ts b/src/lib-public/generators/FA3/Podmiot3.ts index 287b993..38bb1b7 100644 --- a/src/lib-public/generators/FA3/Podmiot3.ts +++ b/src/lib-public/generators/FA3/Podmiot3.ts @@ -20,7 +20,7 @@ export function generatePodmiot3(podmiot: Podmiot3, index: number): Content[] { const column1: Content[] = [ ...createHeader(`Podmiot inny ${index + 1}`), createLabelText('Identyfikator nabywcy: ', podmiot.IDNabywcy), - createLabelText('NrEORI: ', podmiot.NrEORI), + createLabelText('Numer EORI: ', podmiot.NrEORI), ...generateDaneIdentyfikacyjneTPodmiot3Dto(podmiot.DaneIdentyfikacyjne), createLabelText('Rola: ', getRolaString(podmiot.Rola, 3)), createLabelText('Rola inna: ', podmiot.OpisRoli), diff --git a/src/lib-public/generators/FA3/PodmiotDaneKontaktowe.spec.ts b/src/lib-public/generators/FA3/PodmiotDaneKontaktowe.spec.ts index 54da949..7294910 100644 --- a/src/lib-public/generators/FA3/PodmiotDaneKontaktowe.spec.ts +++ b/src/lib-public/generators/FA3/PodmiotDaneKontaktowe.spec.ts @@ -21,11 +21,11 @@ describe(generateDaneKontaktowe.name, () => { it('returns mapped Content array when daneKontaktowe is provided', () => { const result = generateDaneKontaktowe(mockData); expect(getTable).toHaveBeenCalledWith(mockData); - expect(createLabelText).toHaveBeenCalledWith('Email: ', mockData[0].Email); + expect(createLabelText).toHaveBeenCalledWith('E-mail: ', mockData[0].Email); expect(createLabelText).toHaveBeenCalledWith('Tel.: ', mockData[0].Telefon); expect(Array.isArray(result)).toBe(true); expect(result?.length).toBe(2); - expect(result?.[0]).toEqual([{ text: 'Email: test@example.com' }, { text: 'Tel.: 123456789' }]); + expect(result?.[0]).toEqual([{ text: 'E-mail: test@example.com' }, { text: 'Tel.: 123456789' }]); }); it('returns undefined when getTable returns undefined', () => { diff --git a/src/lib-public/generators/FA3/PodmiotDaneKontaktowe.ts b/src/lib-public/generators/FA3/PodmiotDaneKontaktowe.ts index f6289d6..2b26145 100644 --- a/src/lib-public/generators/FA3/PodmiotDaneKontaktowe.ts +++ b/src/lib-public/generators/FA3/PodmiotDaneKontaktowe.ts @@ -5,7 +5,7 @@ import { Podmiot1DaneKontaktowe } from '../../types/fa3.types'; export function generateDaneKontaktowe(daneKontaktowe: Podmiot1DaneKontaktowe[]): Content[] { return getTable(daneKontaktowe)?.map((daneKontaktowe) => { return [ - createLabelText('Email: ', daneKontaktowe.Email), + createLabelText('E-mail: ', daneKontaktowe.Email), createLabelText('Tel.: ', daneKontaktowe.Telefon), ]; }); diff --git a/src/lib-public/generators/FA3/Podmioty.spec.ts b/src/lib-public/generators/FA3/Podmioty.spec.ts index 6431743..2412cdc 100644 --- a/src/lib-public/generators/FA3/Podmioty.spec.ts +++ b/src/lib-public/generators/FA3/Podmioty.spec.ts @@ -14,6 +14,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ createSection: vi.fn((content: any, flag: boolean) => ({ content, flag })), getTable: vi.fn((data: any) => data || []), getValue: vi.fn((val: any) => val?._text ?? val), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), })); vi.mock('./Podmiot1', () => ({ diff --git a/src/lib-public/generators/FA3/Podmioty.ts b/src/lib-public/generators/FA3/Podmioty.ts index d2e2f48..42347a6 100644 --- a/src/lib-public/generators/FA3/Podmioty.ts +++ b/src/lib-public/generators/FA3/Podmioty.ts @@ -1,5 +1,5 @@ import { Content } from 'pdfmake/interfaces'; -import { createSection, getTable, getValue } from '../../../shared/PDF-functions'; +import { createSection, generateColumns, getTable, getValue } from '../../../shared/PDF-functions'; import { Faktura, Podmiot2K, Podmiot3 } from '../../types/fa3.types'; import { Podmiot3Podmiot2KDto } from '../../types/fa2-additional-types'; import { generatePodmiot1 } from './Podmiot1'; @@ -32,10 +32,10 @@ export function generatePodmioty(invoice: Faktura): Content[] { } } else { result.push([ - { - columns: [generatePodmiot1(invoice.Podmiot1!), generatePodmiot2(invoice.Podmiot2!)], + generateColumns([generatePodmiot1(invoice.Podmiot1!), generatePodmiot2(invoice.Podmiot2!)], { margin: [0, 0, 0, 8], - }, + columnGap: 20, + }), ]); } diff --git a/src/lib-public/generators/FA3/RachunekBankowy.spec.ts b/src/lib-public/generators/FA3/RachunekBankowy.spec.ts new file mode 100644 index 0000000..6a7a918 --- /dev/null +++ b/src/lib-public/generators/FA3/RachunekBankowy.spec.ts @@ -0,0 +1,263 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { generujRachunekBankowy } from './RachunekBankowy'; +import * as PDFFunctions from '../../../shared/PDF-functions'; +import { makeBreakable } from '../../../shared/PDF-functions'; +import FormatTyp from '../../../shared/enums/common.enum'; +import { RachunekBankowy } from '../../types/fa3.types'; +import * as CommonFunctions from '../../../shared/generators/common/functions'; + +vi.mock('../../../shared/PDF-functions', () => ({ + createHeader: vi.fn(), + createSection: vi.fn(), + formatText: vi.fn(), + makeBreakable: vi.fn(), + getValue: (val: any) => val?._text || '', + hasValue: (val: any) => val?._text || '', +})); + +vi.mock('../../../shared/generators/common/functions', () => ({ + getTypRachunkowWlasnych: vi.fn(), +})); + +describe(generujRachunekBankowy.name, () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + const mockAccount: RachunekBankowy = { + NrRB: { _text: '12345678901234567890123456' }, + SWIFT: { _text: 'BPKOPLPW' }, + RachunekWlasnyBanku: { _text: '1' }, + NazwaBanku: { _text: 'PKO Bank Polski' }, + OpisRachunku: { _text: 'Rachunek główny' }, + } as any; + + beforeEach(() => { + vi.mocked(PDFFunctions.createHeader).mockReturnValue(['header'] as any); + vi.mocked(PDFFunctions.createSection).mockReturnValue('section' as any); + vi.mocked(PDFFunctions.formatText).mockReturnValue('formatted' as any); + vi.mocked(CommonFunctions.getTypRachunkowWlasnych).mockReturnValue('Tak'); + }); + + describe('when accounts is undefined or empty', () => { + it('should return empty array when accounts is undefined', () => { + const result = generujRachunekBankowy(undefined, 'Rachunek bankowy'); + + expect(result).toEqual([]); + }); + + it('should return empty array when accounts is empty array', () => { + const result = generujRachunekBankowy([], 'Rachunek bankowy'); + + expect(result).toEqual([]); + }); + }); + + describe('when accounts exist', () => { + it('should call createHeader with provided title', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Rachunek bankowy ', [0, 12, 0, 8]); + }); + + it('should call createHeader with empty string when title is not provided', () => { + generujRachunekBankowy([mockAccount]); + + expect(PDFFunctions.createHeader).toHaveBeenCalledWith('', [0, 12, 0, 8]); + }); + + it('should call createSection and return result', () => { + const mockSection = 'section'; + + vi.mocked(PDFFunctions.createSection).mockReturnValue(mockSection as any); + + const result = generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.createSection).toHaveBeenCalledWith(expect.any(Array), false); + expect(result).toEqual(mockSection); + }); + + it('should format "Pełny numer rachunku" field', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Pełny numer rachunku', FormatTyp.GrayBoldTitle); + expect(PDFFunctions.formatText).toHaveBeenCalledWith(mockAccount.NrRB?._text, FormatTyp.Default); + }); + + it('should format "Kod SWIFT" field', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Kod SWIFT', FormatTyp.GrayBoldTitle); + expect(PDFFunctions.formatText).toHaveBeenCalledWith(mockAccount.SWIFT?._text, FormatTyp.Default); + }); + + it('should format "Rachunek własny banku" field', () => { + vi.mocked(CommonFunctions.getTypRachunkowWlasnych).mockReturnValue('Tak'); + + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Rachunek własny banku', FormatTyp.GrayBoldTitle); + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledWith(mockAccount.RachunekWlasnyBanku); + expect(PDFFunctions.formatText).toHaveBeenCalledWith( + mockAccount.NazwaBanku?._text ? makeBreakable('Bank', 20) : 'Tak', + FormatTyp.Default + ); + }); + + it('should format "Nazwa banku" field', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Nazwa banku', FormatTyp.GrayBoldTitle); + expect(PDFFunctions.formatText).toHaveBeenCalledWith( + mockAccount.NazwaBanku?._text ? makeBreakable('Bank', 20) : 'Nazwa banku', + FormatTyp.Default + ); + }); + + it('should format "Opis rachunku" field', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith('Opis rachunku', FormatTyp.GrayBoldTitle); + expect(PDFFunctions.formatText).toHaveBeenCalledWith( + mockAccount.NazwaBanku?._text ? makeBreakable('Bank', 20) : 'Nazwa banku', + FormatTyp.Default + ); + }); + + it('should create table structure with correct widths', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent).toHaveProperty('table'); + expect(tableContent.table).toHaveProperty('widths', ['*', 'auto']); + }); + + it('should create table structure with unbreakable property', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent).toHaveProperty('unbreakable', true); + }); + + it('should create table with correct layout', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent).toHaveProperty('layout'); + expect(tableContent.layout).toHaveProperty('hLineWidth'); + expect(tableContent.layout).toHaveProperty('hLineColor'); + expect(tableContent.layout).toHaveProperty('vLineWidth'); + expect(tableContent.layout).toHaveProperty('vLineColor'); + }); + + it('should create table with correct line colors', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent.layout.hLineColor()).toBe('#BABABA'); + expect(tableContent.layout.vLineColor()).toBe('#BABABA'); + }); + + it('should create table with correct line widths', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent.layout.hLineWidth()).toBe(1); + expect(tableContent.layout.vLineWidth()).toBe(1); + }); + + it('should handle account with undefined fields', () => { + const accountWithUndefined: RachunekBankowy = { + NrRB: { _text: undefined }, + SWIFT: { _text: undefined }, + RachunekWlasnyBanku: { _text: undefined }, + NazwaBanku: { _text: undefined }, + OpisRachunku: { _text: undefined }, + } as any; + + generujRachunekBankowy([accountWithUndefined], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith(undefined, FormatTyp.Default); + }); + }); + + describe('when multiple accounts exist', () => { + it('should create multiple tables for multiple accounts', () => { + const account2: RachunekBankowy = { + NrRB: { _text: '98765432109876543210987654' }, + SWIFT: { _text: 'PKOPPLPW' }, + RachunekWlasnyBanku: { _text: '0' }, + NazwaBanku: { _text: 'mBank' }, + OpisRachunku: { _text: 'Rachunek pomocniczy' }, + } as any; + + generujRachunekBankowy([mockAccount, account2], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + + expect(sectionCall.length).toBe(2); + }); + + it('should call getTypRachunkowWlasnych for each account', () => { + const account2: RachunekBankowy = { + NrRB: { _text: '98765432109876543210987654' }, + SWIFT: { _text: 'PKOPPLPW' }, + RachunekWlasnyBanku: { _text: '0' }, + NazwaBanku: { _text: 'mBank' }, + OpisRachunku: { _text: 'Rachunek pomocniczy' }, + } as any; + + generujRachunekBankowy([mockAccount, account2], 'Rachunek bankowy'); + + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledTimes(2); + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledWith(mockAccount.RachunekWlasnyBanku); + expect(CommonFunctions.getTypRachunkowWlasnych).toHaveBeenCalledWith(account2.RachunekWlasnyBanku); + }); + + it('should format all fields for all accounts', () => { + const account2: RachunekBankowy = { + NrRB: { _text: '98765432109876543210987654' }, + SWIFT: { _text: 'PKOPPLPW' }, + RachunekWlasnyBanku: { _text: '0' }, + NazwaBanku: { _text: 'mBank' }, + OpisRachunku: { _text: 'Rachunek pomocniczy' }, + } as any; + + generujRachunekBankowy([mockAccount, account2], 'Rachunek bankowy'); + + expect(PDFFunctions.formatText).toHaveBeenCalledWith(mockAccount.NrRB?._text, FormatTyp.Default); + expect(PDFFunctions.formatText).toHaveBeenCalledWith(account2.NrRB?._text, FormatTyp.Default); + }); + }); + + describe('table structure', () => { + it('should create table with 5 rows', () => { + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + const tableContent = sectionCall[0][1]; + + expect(tableContent.table.body.length).toBe(5); + }); + + it('should include header in result array', () => { + vi.mocked(PDFFunctions.createHeader).mockReturnValue(['header-content'] as any); + + generujRachunekBankowy([mockAccount], 'Rachunek bankowy'); + + const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[]; + + expect(sectionCall[0][0]).toBe('header-content'); + }); + }); +}); diff --git a/src/lib-public/generators/FA3/RachunekBankowy.ts b/src/lib-public/generators/FA3/RachunekBankowy.ts index 63047b1..67ac321 100644 --- a/src/lib-public/generators/FA3/RachunekBankowy.ts +++ b/src/lib-public/generators/FA3/RachunekBankowy.ts @@ -1,5 +1,12 @@ import { Content, ContentTable } from 'pdfmake/interfaces'; -import { createHeader, createSection, formatText } from '../../../shared/PDF-functions'; +import { + createHeader, + createSection, + formatText, + getValue, + hasValue, + makeBreakable, +} from '../../../shared/PDF-functions'; import FormatTyp from '../../../shared/enums/common.enum'; import { RachunekBankowy } from '../../types/fa3.types'; import { getTypRachunkowWlasnych } from '../../../shared/generators/common/functions'; @@ -20,23 +27,33 @@ export const generujRachunekBankowy = (accounts?: RachunekBankowy[], title?: str table.push([ formatText('Pełny numer rachunku', FormatTyp.GrayBoldTitle), - formatText(account.NrRB?._text, FormatTyp.Default), + formatText(getValue(account.NrRB), FormatTyp.Default), ]); table.push([ formatText('Kod SWIFT', FormatTyp.GrayBoldTitle), - formatText(account.SWIFT?._text, FormatTyp.Default), + formatText(getValue(account.SWIFT), FormatTyp.Default), ]); table.push([ formatText('Rachunek własny banku', FormatTyp.GrayBoldTitle), - formatText(getTypRachunkowWlasnych(account.RachunekWlasnyBanku), FormatTyp.Default), + formatText(makeBreakable(getTypRachunkowWlasnych(account.RachunekWlasnyBanku), 20), FormatTyp.Default), ]); table.push([ formatText('Nazwa banku', FormatTyp.GrayBoldTitle), - formatText(account.NazwaBanku?._text, FormatTyp.Default), + formatText( + hasValue(account.NazwaBanku) + ? makeBreakable(getValue(account.NazwaBanku), 20) + : getValue(account.NazwaBanku), + FormatTyp.Default + ), ]); table.push([ formatText('Opis rachunku', FormatTyp.GrayBoldTitle), - formatText(account.OpisRachunku?._text, FormatTyp.Default), + formatText( + hasValue(account.OpisRachunku) + ? makeBreakable(getValue(account.OpisRachunku), 20) + : getValue(account.OpisRachunku), + FormatTyp.Default + ), ]); result.push([ ...base, diff --git a/src/lib-public/generators/FA3/WarunkiTransakcji.spec.ts b/src/lib-public/generators/FA3/WarunkiTransakcji.spec.ts index d98aba8..3159105 100644 --- a/src/lib-public/generators/FA3/WarunkiTransakcji.spec.ts +++ b/src/lib-public/generators/FA3/WarunkiTransakcji.spec.ts @@ -125,7 +125,9 @@ describe(generateWarunkiTransakcji.name, () => { expect.objectContaining({ name: 'NrUmowy', title: 'Numer umowy' }), ]), expect.any(Array), - '*' + '*', + undefined, + 20 ); }); @@ -173,7 +175,9 @@ describe(generateWarunkiTransakcji.name, () => { expect.objectContaining({ name: 'NrZamowienia', title: 'Numer zamówienia' }), ]), expect.any(Array), - '*' + '*', + undefined, + 20 ); }); diff --git a/src/lib-public/generators/FA3/WarunkiTransakcji.ts b/src/lib-public/generators/FA3/WarunkiTransakcji.ts index 8caea22..abb5347 100644 --- a/src/lib-public/generators/FA3/WarunkiTransakcji.ts +++ b/src/lib-public/generators/FA3/WarunkiTransakcji.ts @@ -38,14 +38,20 @@ export function generateWarunkiTransakcji(warunkiTransakcji: WarunkiTransakcji | table.push(createHeader('Warunki transakcji', [0, 8, 0, 4])); if (umowy.length > 0) { - const tabUmowy = getContentTable<(typeof umowy)[0]>(definedHeaderUmowy, umowy, '*'); + const tabUmowy = getContentTable<(typeof umowy)[0]>(definedHeaderUmowy, umowy, '*', undefined, 20); if (tabUmowy.content) { Kolumny.umowy = [createSubHeader('Umowa'), tabUmowy.content]; } } if (zamowienia.length > 0) { - const tabZamowienia = getContentTable<(typeof zamowienia)[0]>(definedHeaderZamowienia, zamowienia, '*'); + const tabZamowienia = getContentTable<(typeof zamowienia)[0]>( + definedHeaderZamowienia, + zamowienia, + '*', + undefined, + 20 + ); if (tabZamowienia.content && tabZamowienia.fieldsWithValue.length > 0) { Kolumny.zamowienia = [createSubHeader('Zamówienie'), tabZamowienia.content]; diff --git a/src/lib-public/generators/common/Rozliczenie.spec.ts b/src/lib-public/generators/common/Rozliczenie.spec.ts index f1beead..2f50b08 100644 --- a/src/lib-public/generators/common/Rozliczenie.spec.ts +++ b/src/lib-public/generators/common/Rozliczenie.spec.ts @@ -6,6 +6,7 @@ vi.mock('../../../shared/PDF-functions', () => ({ createHeader: vi.fn((...args) => ({ header: args[0], margin: args[1] })), createSubHeader: vi.fn((label) => ({ subHeader: label })), generateTwoColumns: vi.fn((left, right) => ({ columns: [left, right] })), + generateColumns: vi.fn((left, right) => ({ columns: [left, right] })), getTable: vi.fn((rows) => rows ?? []), getContentTable: vi.fn((header, rows) => ({ content: rows })), createLabelText: vi.fn((label, value) => ({ label, value })), diff --git a/src/lib-public/generators/common/Rozliczenie.ts b/src/lib-public/generators/common/Rozliczenie.ts index feaabb9..bb03472 100644 --- a/src/lib-public/generators/common/Rozliczenie.ts +++ b/src/lib-public/generators/common/Rozliczenie.ts @@ -5,6 +5,7 @@ import { createLabelTextArray, createSection, createSubHeader, + generateColumns, generateTwoColumns, getContentTable, getTable, @@ -52,12 +53,16 @@ export function generateRozliczenie( const tableObciazenia: FormContentState = getContentTable<(typeof obciazenia)[0]>( headerObciazenia, obciazenia, - '*' + '*', + undefined, + 20 ); const tableOdliczenia: FormContentState = getContentTable<(typeof odliczenia)[0]>( headerOdliczenia, odliczenia, - '*' + '*', + undefined, + 20 ); const SumaObciazen: Content[] = createLabelText( 'Suma kwot obciążenia: ', @@ -88,7 +93,7 @@ export function generateRozliczenie( result.push(createHeader('Rozliczenie', [0, 8, 0, 4])); if (obciazenia.length > 0 && odliczenia.length > 0) { - result.push(generateTwoColumns([resultObciazenia], [resultOdliczenia])); + result.push(generateColumns([resultObciazenia, resultOdliczenia])); } else if (obciazenia.length > 0) { result.push(generateTwoColumns([resultObciazenia], [])); } else if (odliczenia.length > 0) { diff --git a/src/shared/PDF-functions.spec.ts b/src/shared/PDF-functions.spec.ts index 90d11ad..ffcccae 100644 --- a/src/shared/PDF-functions.spec.ts +++ b/src/shared/PDF-functions.spec.ts @@ -26,7 +26,7 @@ describe('formatText', () => { expect(content).toEqual( expect.objectContaining({ alignment: Position.RIGHT, - text: '100.00 PLN', + text: '100,00 PLN', style: FormatTyp.Currency, bold: true, }) diff --git a/src/shared/PDF-functions.ts b/src/shared/PDF-functions.ts index 61df63b..99e6d47 100644 --- a/src/shared/PDF-functions.ts +++ b/src/shared/PDF-functions.ts @@ -75,21 +75,27 @@ function formatValue( ): void { switch (item) { case FormatTyp.Currency: - result.text = isNaN(Number(value)) ? (value as string) : `${Number(value).toFixed(2)} ${currency}`; + result.text = isNaN(Number(value)) + ? (value as string) + : `${dotToComma(Number(value).toFixed(2))} ${currency}`; result.alignment = Position.RIGHT; break; case FormatTyp.CurrencyAbs: result.text = isNaN(Number(value)) ? (value as string) - : `${Math.abs(Number(value)).toFixed(2)} ${currency}`; + : `${dotToComma(Math.abs(Number(value)).toFixed(2))} ${currency}`; result.alignment = Position.RIGHT; break; case FormatTyp.CurrencyGreater: - result.text = isNaN(Number(value)) ? (value as string) : `${Number(value).toFixed(2)} ${currency}`; + result.text = isNaN(Number(value)) + ? (value as string) + : `${dotToComma(Number(value).toFixed(2))} ${currency}`; result.fontSize = 10; break; case FormatTyp.Currency6: - result.text = isNaN(Number(value)) ? (value as string) : `${Number(value).toFixed(6)} ${currency}`; + result.text = isNaN(Number(value)) + ? (value as string) + : `${dotToComma(Number(value).toFixed(6))} ${currency}`; result.alignment = Position.RIGHT; break; case FormatTyp.DateTime: @@ -110,6 +116,10 @@ function formatValue( } } +function dotToComma(value: string): string { + return value.replace('.', ','); +} + export function hasValue(value: FP | string | number | undefined): boolean { return ( !!((typeof value !== 'object' && value) || (typeof value === 'object' && value._text)) || value === 0 @@ -356,7 +366,8 @@ export function getContentTable( headers: HeaderDefine[], data: T[], defaultWidths: string, - margin?: Margins + margin?: Margins, + wordBreak?: number ): { content: ContentTable | null; fieldsWithValue: string[] } { const fieldsWithValue: HeaderDefine[] = headers.filter((header: HeaderDefine): boolean => { return data.some((d: T): boolean => { @@ -392,7 +403,10 @@ export function getContentTable( const value: string | undefined = typeof fp === 'object' ? fp?._text : fp; return formatText( - header.mappingData && value ? header.mappingData[value] : (value ?? ''), + makeBreakable( + header.mappingData && value ? header.mappingData[value] : (value ?? ''), + wordBreak ?? 40 + ), header.format ?? FormatTyp.Default, { rowSpan: fp?._rowSpan ?? 1 } ); @@ -417,10 +431,22 @@ export function getContentTable( export function generateTwoColumns(kol1: Column, kol2: Column, margin?: Margins): Content { return { columns: [ - { stack: [kol1], margin: [0, 0, 5, 0] }, - { stack: [kol2], margin: [5, 0, 0, 0] }, + { stack: [kol1], width: '50%' }, + { stack: [kol2], width: '50%' }, ], margin: margin ?? [0, 0, 0, 0], + columnGap: 20, + }; +} + +export function generateColumns(contents: Content[][], style: Style | undefined = undefined): Content { + const width: string = (100 / contents.length).toFixed(0) + '%'; + const columns: Column = contents.map((content: Content[]) => ({ stack: content, width })); + const columnStyle: Style = style ? { ...style } : { columnGap: 20 }; + + return { + columns, + ...columnStyle, }; } @@ -464,3 +490,13 @@ export function generateLine(): Content { } as CustomTableLayout, }; } + +export function makeBreakable( + value: string | number | undefined, + wordBreak = 40 +): string | number | undefined { + if (typeof value === 'string') { + return value.replace(new RegExp(`(.{${wordBreak}})`, 'g'), '$1\u200B'); + } + return value; +} diff --git a/src/shared/consts/const.ts b/src/shared/consts/const.ts index 225cdd3..d8e09c9 100644 --- a/src/shared/consts/const.ts +++ b/src/shared/consts/const.ts @@ -404,3 +404,10 @@ export const DEFAULT_TABLE_LAYOUT: { vLineWidth: (): number => 1, vLineColor: (): string => '#BABABA', }; + +export const TAXPAYER_STATUS: Record = { + '1': 'Stan likwidacji', + '2': 'Postępowanie restrukturyzacyjne', + '3': 'Stan upadłości', + '4': 'Przedsiębiorstwo w spadku', +};