fix build config & fixes for invoice FA1/FA2/FA3

This commit is contained in:
Michał Chudy
2025-12-03 13:42:56 +01:00
parent b9972746aa
commit 1912b5b48d
68 changed files with 1144 additions and 227 deletions

4
package-lock.json generated
View File

@@ -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",

View File

@@ -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": [],

View File

@@ -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, () => {

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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' }]));
});
});

View File

@@ -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;
}

View File

@@ -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 })),

View File

@@ -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));

View File

@@ -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' }])
);
});

View File

@@ -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));
}

View File

@@ -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 })),

View File

@@ -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));

View File

@@ -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' },

View File

@@ -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)) {

View File

@@ -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)) {

View File

@@ -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 }]),

View File

@@ -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,
}),
]);
}

View File

@@ -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');
});
});
});

View File

@@ -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<string, FP>[], 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,

View File

@@ -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', () => {

View File

@@ -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) {

View File

@@ -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);
});
});

View File

@@ -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[] = [

View File

@@ -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<Podmiot1> = {
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<Podmiot1> = {
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);
});
});

View File

@@ -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;
}

View File

@@ -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 });
});

View File

@@ -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));

View File

@@ -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);

View File

@@ -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(

View File

@@ -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(

View File

@@ -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');
});

View File

@@ -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));

View File

@@ -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),

View File

@@ -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', () => {

View File

@@ -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),
];
});

View File

@@ -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', () => ({

View File

@@ -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,
}),
]);
}

View File

@@ -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<string, FP> = {
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<string, FP> = {
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<string, FP> = {
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<string, FP> = {
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<string, FP> = {
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');
});
});
});

View File

@@ -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<string, FP>[], 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,

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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);
});
});

View File

@@ -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,

View File

@@ -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(

View File

@@ -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<Podmiot1> = {
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<Podmiot1> = {
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);
});
});

View File

@@ -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;
}

View File

@@ -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 });
});
});

View File

@@ -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));

View File

@@ -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');
});

View File

@@ -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(

View File

@@ -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');
});
});

View File

@@ -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));

View File

@@ -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),

View File

@@ -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', () => {

View File

@@ -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),
];
});

View File

@@ -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', () => ({

View File

@@ -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,
}),
]);
}

View File

@@ -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');
});
});
});

View File

@@ -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,

View File

@@ -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
);
});

View File

@@ -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];

View File

@@ -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 })),

View File

@@ -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) {

View File

@@ -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,
})

View File

@@ -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<T>(
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<T>(
const value: string | undefined = typeof fp === 'object' ? fp?._text : fp;
return formatText(
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<T>(
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;
}

View File

@@ -404,3 +404,10 @@ export const DEFAULT_TABLE_LAYOUT: {
vLineWidth: (): number => 1,
vLineColor: (): string => '#BABABA',
};
export const TAXPAYER_STATUS: Record<string, string> = {
'1': 'Stan likwidacji',
'2': 'Postępowanie restrukturyzacyjne',
'3': 'Stan upadłości',
'4': 'Przedsiębiorstwo w spadku',
};