UPO 4.3, fixes for invoices
This commit is contained in:
@@ -1,22 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Potwierdzenie xmlns="http://upo.schematy.mf.gov.pl/KSeF/v4-2">
|
||||
<NazwaPodmiotuPrzyjmujacego>Ministerstwo Finansów</NazwaPodmiotuPrzyjmujacego>
|
||||
<NumerReferencyjnySesji>36950822-93-9D5A28BFDA-47C899773E-5C</NumerReferencyjnySesji>
|
||||
<Uwierzytelnienie>
|
||||
<IdKontekstu>
|
||||
<IdZlozonyVatUE>5265877635-ATU12345678</IdZlozonyVatUE>
|
||||
</IdKontekstu>
|
||||
<SkrotDokumentuUwierzytelniajacego>kyqH+QUgP8ATWd/95IY632mP4uqibwG66Oqclq9+qno=</SkrotDokumentuUwierzytelniajacego>
|
||||
</Uwierzytelnienie>
|
||||
<NazwaStrukturyLogicznej>1-0E</NazwaStrukturyLogicznej>
|
||||
<KodFormularza>FA (3)</KodFormularza>
|
||||
<Dokument>
|
||||
<NipSprzedawcy>5265877635</NipSprzedawcy>
|
||||
<NumerKSeFDokumentu>5265877635-20250916-0200A0D6723E-C2</NumerKSeFDokumentu>
|
||||
<NumerFaktury>FA/XVQUD-9997622510/04/2027</NumerFaktury>
|
||||
<DataWystawieniaFaktury>2025-09-16</DataWystawieniaFaktury>
|
||||
<DataPrzeslaniaDokumentu>2025-09-16T11:05:40.841+02:00</DataPrzeslaniaDokumentu>
|
||||
<DataNadaniaNumeruKSeF>2025-09-16T11:05:41.045+02:00</DataNadaniaNumeruKSeF>
|
||||
<SkrotDokumentu>GZMGNVzs3krF6URKgvaw77OOeG3nJ+WGziT5xguliQ8=</SkrotDokumentu>
|
||||
</Dokument>
|
||||
<Potwierdzenie xmlns="http://upo.schematy.mf.gov.pl/KSeF/v4-3">
|
||||
<NazwaPodmiotuPrzyjmujacego>Ministerstwo Finansów</NazwaPodmiotuPrzyjmujacego>
|
||||
<NumerReferencyjnySesji>36950822-93-9D5A28BFDA-47C899773E-5C</NumerReferencyjnySesji>
|
||||
<Uwierzytelnienie>
|
||||
<IdKontekstu>
|
||||
<IdZlozonyVatUE>5265877635-ATU12345678</IdZlozonyVatUE>
|
||||
</IdKontekstu>
|
||||
<SkrotDokumentuUwierzytelniajacego>kyqH+QUgP8ATWd/95IY632mP4uqibwG66Oqclq9+qno=
|
||||
</SkrotDokumentuUwierzytelniajacego>
|
||||
</Uwierzytelnienie>
|
||||
<NazwaStrukturyLogicznej>1-0E</NazwaStrukturyLogicznej>
|
||||
<KodFormularza>FA (3)</KodFormularza>
|
||||
<Dokument>
|
||||
<NipSprzedawcy>5265877635</NipSprzedawcy>
|
||||
<NumerKSeFDokumentu>5265877635-20250916-0200A0D6723E-C2</NumerKSeFDokumentu>
|
||||
<NumerFaktury>FA/XVQUD-9997622510/04/2027</NumerFaktury>
|
||||
<DataWystawieniaFaktury>2025-09-16</DataWystawieniaFaktury>
|
||||
<DataPrzeslaniaDokumentu>2025-09-16T11:05:40.841+02:00</DataPrzeslaniaDokumentu>
|
||||
<DataNadaniaNumeruKSeF>2025-09-16T11:05:41.045+02:00</DataNadaniaNumeruKSeF>
|
||||
<SkrotDokumentu>GZMGNVzs3krF6URKgvaw77OOeG3nJ+WGziT5xguliQ8=</SkrotDokumentu>
|
||||
<TrybWysylki>Offline</TrybWysylki>
|
||||
</Dokument>
|
||||
</Potwierdzenie>
|
||||
1303
package-lock.json
generated
1303
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@akmf/ksef-fe-invoice-converter",
|
||||
"version": "0.0.32",
|
||||
"version": "0.0.42",
|
||||
"scripts": {
|
||||
"dev": "vite --mode public --config vite.config.ts",
|
||||
"build": "vite build --mode production",
|
||||
|
||||
@@ -1,19 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>KSEF PDF GENERATOR</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="margin: auto;width: fit-content">📄 KSEF PDF GENERATOR</h1>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>XML Parser</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>📄 XML Parser</h1>
|
||||
|
||||
<h1> Wygeneruj wizualizacje faktury PDF </h1>
|
||||
<input accept=".xml" id="xmlInput" type="file" />
|
||||
<h2>Wygeneruj fakture:</h2>
|
||||
<input
|
||||
accept=".xml"
|
||||
id="xmlInput"
|
||||
type="file"
|
||||
/>
|
||||
|
||||
<h1> Wygeneruj wizualizacje UPO PDF</h1>
|
||||
<input accept=".xml" id="xmlInputUPO" type="file" />
|
||||
<h2>Wygeneruj UPO:</h2>
|
||||
<input
|
||||
accept=".xml"
|
||||
id="xmlInputUPO"
|
||||
type="file"
|
||||
/>
|
||||
|
||||
|
||||
<script src="./main.ts" type="module"></script>
|
||||
</body>
|
||||
<script
|
||||
src="./main.ts"
|
||||
type="module"
|
||||
></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -15,7 +15,7 @@ inputInvoice.addEventListener('change', async (): Promise<void> => {
|
||||
const additionalData: AdditionalDataTypes = {
|
||||
nrKSeF: '5555555555-20250808-9231003CA67B-BE',
|
||||
qrCode:
|
||||
'https://ksef-test.mf.gov.pl/client-app/invoice/5265877635/26-10-2025/HS5E1zrA8WVjDNq_xMVIN5SD6nyRymmQ-BcYHReUAa0',
|
||||
'https://qr-test.ksef.mf.gov.pl/invoice/5265877635/26-10-2025/HS5E1zrA8WVjDNq_xMVIN5SD6nyRymmQ-BcYHReUAa0',
|
||||
};
|
||||
|
||||
generateInvoice(file, additionalData, 'blob').then((data: Blob): void => {
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
export { generateInvoice, generatePDFUPO } from './lib-public';
|
||||
export { generateFA1 } from './lib-public/FA1-generator';
|
||||
export { generateFA2 } from './lib-public/FA2-generator';
|
||||
export { generateFA3 } from './lib-public/FA3-generator';
|
||||
export { generateNaglowekUPO } from './lib-public/generators/UPO4_3/Naglowek';
|
||||
export { generateDokumentUPO } from './lib-public/generators/UPO4_3/Dokumenty';
|
||||
export { generateStyle } from './shared/PDF-functions';
|
||||
export * from './shared/enums/common.enum';
|
||||
|
||||
65
src/lib-public/UPO-generator.spec.ts
Normal file
65
src/lib-public/UPO-generator.spec.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import pdfMake from 'pdfmake/build/pdfmake';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generatePDFUPO } from './UPO-generator';
|
||||
import * as XMLParser from '../shared/XML-parser';
|
||||
|
||||
describe('generatePDFUPO', () => {
|
||||
const dummyFile = new File(['dummy'], 'dummy.xml', { type: 'text/xml' });
|
||||
const dummyUpo = {
|
||||
Potwierdzenie: {
|
||||
field1: 'value1',
|
||||
field2: 'value2',
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.spyOn(XMLParser, 'parseXML').mockResolvedValue(dummyUpo);
|
||||
|
||||
vi.spyOn(pdfMake, 'createPdf').mockImplementation(
|
||||
() =>
|
||||
({
|
||||
getBlob: (callback: (blob: Blob | null) => void) => {
|
||||
const blob = new Blob(['PDF content'], { type: 'application/pdf' });
|
||||
|
||||
callback(blob);
|
||||
},
|
||||
}) as any
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('successfully generates a PDF blob', async () => {
|
||||
const blob = await generatePDFUPO(dummyFile);
|
||||
|
||||
expect(blob).toBeInstanceOf(Blob);
|
||||
const text = await new Promise<string>((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (): void => resolve(reader.result as string);
|
||||
reader.onerror = (): void => reject(reader.error);
|
||||
reader.readAsText(blob);
|
||||
});
|
||||
|
||||
expect(text).toContain('PDF content');
|
||||
});
|
||||
|
||||
it('rejects promise if pdfMake returns null blob', async () => {
|
||||
vi.spyOn(pdfMake, 'createPdf').mockReturnValue({
|
||||
getBlob: (callback: (blob: Blob | null) => void) => {
|
||||
callback(null);
|
||||
},
|
||||
} as any);
|
||||
|
||||
await expect(generatePDFUPO(dummyFile)).rejects.toEqual('Error');
|
||||
});
|
||||
|
||||
it('calls parseXML with the input file', async () => {
|
||||
const parseXMLSpy = vi.spyOn(XMLParser, 'parseXML');
|
||||
|
||||
await generatePDFUPO(dummyFile);
|
||||
expect(parseXMLSpy).toHaveBeenCalledWith(dummyFile);
|
||||
});
|
||||
});
|
||||
35
src/lib-public/UPO-generator.ts
Normal file
35
src/lib-public/UPO-generator.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import pdfMake from 'pdfmake/build/pdfmake';
|
||||
import { Upo } from './types/upo-v4_2.types';
|
||||
import { TDocumentDefinitions } from 'pdfmake/interfaces';
|
||||
import { generateStyle } from '../shared/PDF-functions';
|
||||
import { parseXML } from '../shared/XML-parser';
|
||||
import { Position } from '../shared/enums/common.enum';
|
||||
import { generateDokumentUPO } from './generators/UPO4_3/Dokumenty';
|
||||
import { generateNaglowekUPO } from './generators/UPO4_3/Naglowek';
|
||||
|
||||
export async function generatePDFUPO(file: File): Promise<Blob> {
|
||||
const upo = (await parseXML(file)) as Upo;
|
||||
const docDefinition: TDocumentDefinitions = {
|
||||
content: [generateNaglowekUPO(upo.Potwierdzenie!), generateDokumentUPO(upo.Potwierdzenie!)],
|
||||
...generateStyle(),
|
||||
pageSize: 'A4',
|
||||
pageOrientation: 'landscape',
|
||||
footer: function (currentPage: number, pageCount: number) {
|
||||
return {
|
||||
text: currentPage.toString() + ' z ' + pageCount,
|
||||
alignment: Position.RIGHT,
|
||||
margin: [0, 0, 20, 0],
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject): void => {
|
||||
pdfMake.createPdf(docDefinition).getBlob((blob: Blob): void => {
|
||||
if (blob) {
|
||||
resolve(blob);
|
||||
} else {
|
||||
reject('Error');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -52,7 +52,7 @@ export function generatePlatnosc(platnosc: Platnosc | undefined): Content {
|
||||
|
||||
if (platnosc.Zaplacono?._text === '1') {
|
||||
table.push(createLabelText('Informacja o płatności: ', 'Zapłacono'));
|
||||
table.push(createLabelText('Data zapłaty: ', platnosc.DataZaplaty));
|
||||
table.push(createLabelText('Data zapłaty: ', platnosc.DataZaplaty, FormatTyp.Date));
|
||||
} else if (platnosc.ZaplataCzesciowa?._text === '1') {
|
||||
table.push(createLabelText('Informacja o płatności: ', 'Zapłata częściowa'));
|
||||
} else {
|
||||
|
||||
@@ -36,8 +36,11 @@ export function generatePodmiot2Podmiot2K(podmiot2: Podmiot2, podmiot2K: Podmiot
|
||||
columnGap: 20,
|
||||
});
|
||||
}
|
||||
firstColumn = generateCorrectedContent(podmiot2K, 'Treść korygowana');
|
||||
secondColumn = generateCorrectedContent(podmiot2, 'Treść korygująca');
|
||||
if(podmiot2K.Adres?.AdresPol || podmiot2K.Adres?.AdresZagr) {
|
||||
firstColumn = generateCorrectedContent(podmiot2K, 'Treść korygowana');
|
||||
secondColumn = generateCorrectedContent(podmiot2, 'Treść korygująca');
|
||||
}
|
||||
|
||||
if (podmiot2.AdresKoresp) {
|
||||
secondColumn.push(
|
||||
generatePodmiotAdres(podmiot2.AdresKoresp, 'Adres do korespondencji', true, [0, 12, 0, 1.3])
|
||||
|
||||
@@ -79,6 +79,7 @@ describe('getSummaryTaxRate', () => {
|
||||
gross: '123.00',
|
||||
});
|
||||
expect(summary[1].taxRateString).toBe('8% lub 7%');
|
||||
expect(summary[3].taxRateString).toBe('4% lub 3%');
|
||||
expect(summary[4].taxRateString).toBe('');
|
||||
expect(summary[5].taxRateString).toBe('zwolnione z opodatkowania');
|
||||
});
|
||||
|
||||
@@ -153,7 +153,7 @@ export function getSummaryTaxRate(fa: Fa): TaxSummaryTypes[] {
|
||||
gross: (getNumberRounded(fa.P_13_4) + getNumberRounded(fa.P_14_4)).toFixed(2),
|
||||
tax: getNumberRounded(fa.P_14_4).toFixed(2),
|
||||
taxPLN: getNumberRounded(fa.P_14_4W).toFixed(2),
|
||||
taxRateString: '4% lub 3% lub oo',
|
||||
taxRateString: '4% lub 3%',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ describe(generateRabat.name, () => {
|
||||
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ name: 'NrWierszaFay', title: 'Lp.' }),
|
||||
expect.objectContaining({ name: 'NrWierszaFa', title: 'Lp.' }),
|
||||
expect.objectContaining({ name: 'P_7', title: 'Nazwa towaru lub usługi' }),
|
||||
expect.objectContaining({ name: 'P_8B', title: 'Ilość' }),
|
||||
expect.objectContaining({ name: 'P_8A', title: 'Miara' }),
|
||||
|
||||
@@ -17,7 +17,7 @@ export function generateRabat(invoice: Fa): Content[] {
|
||||
const faRows: Record<string, FP>[] = getTable(invoice!.FaWiersze?.FaWiersz);
|
||||
const result: Content[] = [];
|
||||
const definedHeader: HeaderDefine[] = [
|
||||
{ name: 'NrWierszaFay', title: 'Lp.', format: FormatTyp.Default },
|
||||
{ name: 'NrWierszaFa', title: 'Lp.', format: FormatTyp.Default },
|
||||
{ name: 'P_7', title: 'Nazwa towaru lub usługi', format: FormatTyp.Default },
|
||||
{ name: 'P_8B', title: 'Ilość', format: FormatTyp.Default },
|
||||
{ name: 'P_8A', title: 'Miara', format: FormatTyp.Default },
|
||||
|
||||
@@ -67,14 +67,19 @@ describe(generateSzczegoly.name, () => {
|
||||
describe('P_6 label', () => {
|
||||
it('uses "Data otrzymania zapłaty" for ZAL', () => {
|
||||
generateSzczegoly({ ...mockFaVat, RodzajFaktury: TRodzajFaktury.ZAL } as any);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Data otrzymania zapłaty: ', mockFaVat.P_6);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data otrzymania zapłaty: ',
|
||||
mockFaVat.P_6,
|
||||
FormatTyp.Date
|
||||
);
|
||||
});
|
||||
|
||||
it('uses "Data dokonania lub zakończenia dostawy" for VAT', () => {
|
||||
generateSzczegoly(mockFaVat);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data dokonania lub zakończenia dostawy towarów lub wykonania usługi: ',
|
||||
mockFaVat.P_6
|
||||
mockFaVat.P_6,
|
||||
FormatTyp.Date
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -82,10 +82,14 @@ export function generateSzczegoly(faVat: Fa): Content[] {
|
||||
|
||||
const forColumns: Content[][] = [
|
||||
createLabelText('Numer faktury: ', faVat.P_2),
|
||||
createLabelText('Data wystawienia, z zastrzeżeniem art. 106na ust. 1 ustawy: ', faVat.P_1),
|
||||
createLabelText(
|
||||
'Data wystawienia, z zastrzeżeniem art. 106na ust. 1 ustawy: ',
|
||||
faVat.P_1,
|
||||
FormatTyp.Date
|
||||
),
|
||||
createLabelText('Miejsce wystawienia: ', faVat.P_1M),
|
||||
createLabelText('Okres, którego dotyczy rabat: ', faVat.OkresFaKorygowanej),
|
||||
createLabelText(LabelP_6, faVat.P_6),
|
||||
createLabelText(LabelP_6, faVat.P_6, FormatTyp.Date),
|
||||
P_6Scope,
|
||||
cenyLabel1,
|
||||
cenyLabel2,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import * as PDFFunctions from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { TRodzajFaktury } from '../../../shared/consts/const';
|
||||
import {TRodzajFaktury} from '../../../shared/consts/const';
|
||||
import { Fa } from '../../types/fa1.types';
|
||||
import { generateWiersze } from './Wiersze';
|
||||
|
||||
@@ -13,6 +13,7 @@ vi.mock('../../../shared/PDF-functions', () => ({
|
||||
getContentTable: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
getValue: vi.fn(),
|
||||
getTStawkaPodatku: vi.fn()
|
||||
}));
|
||||
|
||||
describe(generateWiersze.name, () => {
|
||||
@@ -27,6 +28,7 @@ describe(generateWiersze.name, () => {
|
||||
P_7: { _text: 'Product 1' },
|
||||
P_9A: { _text: '100' },
|
||||
P_8B: { _text: '2' },
|
||||
P_12: { _text: '23' },
|
||||
},
|
||||
],
|
||||
KodWaluty: { _text: 'PLN' },
|
||||
@@ -106,7 +108,7 @@ describe(generateWiersze.name, () => {
|
||||
});
|
||||
|
||||
it('should display "brutto" when P_11 is not in fieldsWithValue', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' }, P_12: {_text: '23'} }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
@@ -117,6 +119,7 @@ describe(generateWiersze.name, () => {
|
||||
vi.mocked(PDFFunctions.formatText).mockReturnValue('formatted text' as any);
|
||||
vi.mocked(PDFFunctions.createHeader).mockReturnValue(['Header'] as any);
|
||||
vi.mocked(PDFFunctions.createSection).mockReturnValue({ section: 'content' } as any);
|
||||
vi.mocked(PDFFunctions.getTStawkaPodatku).mockReturnValue('23');
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
@@ -148,7 +151,7 @@ describe(generateWiersze.name, () => {
|
||||
});
|
||||
|
||||
it('should generate two tables when fieldsWithValue.length > 8', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' }, P_12: {_text: '23'} }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable)
|
||||
.mockReturnValueOnce({
|
||||
@@ -175,7 +178,7 @@ describe(generateWiersze.name, () => {
|
||||
});
|
||||
|
||||
it('should not add second table if it has only 1 field with value', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' }, P_12: {_text: '23'} }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable)
|
||||
.mockReturnValueOnce({
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
formatText,
|
||||
getContentTable,
|
||||
getTable,
|
||||
getTStawkaPodatku,
|
||||
getValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
@@ -13,16 +14,20 @@ import { Procedura, TRodzajFaktury } from '../../../shared/consts/const';
|
||||
import { Fa, FP } from '../../types/fa1.types';
|
||||
import FormatTyp, { Position } from '../../../shared/enums/common.enum';
|
||||
import { FormContentState } from '../../../shared/types/additional-data.types';
|
||||
import { shouldAddMarza } from '../common/Wiersze';
|
||||
import { addMarza } from '../common/Wiersze';
|
||||
|
||||
export function generateWiersze(faVat: Fa): Content {
|
||||
const table: Content[] = [];
|
||||
const rodzajFaktury: string | number | undefined = getValue(faVat.RodzajFaktury);
|
||||
const isP_PMarzy: boolean = Boolean(Number(getValue(faVat.Adnotacje?.P_PMarzy)));
|
||||
const isP_PMarzy = Boolean(Number(getValue(faVat.Adnotacje?.P_PMarzy)));
|
||||
const faWiersze: Record<string, FP>[] = getTable(faVat.FaWiersze?.FaWiersz).map(
|
||||
(wiersz: Record<string, FP>): Record<string, FP> => {
|
||||
const marza: Record<string, FP> = shouldAddMarza(rodzajFaktury, isP_PMarzy, wiersz)!;
|
||||
return marza ? { ...wiersz, ...marza } : wiersz;
|
||||
const marza: Record<string, FP> = addMarza(rodzajFaktury, isP_PMarzy, wiersz)!;
|
||||
|
||||
if (getValue(wiersz.P_12)) {
|
||||
wiersz.P_12._text = getTStawkaPodatku(getValue(wiersz.P_12) as string, 1);
|
||||
}
|
||||
return { ...wiersz, ...marza };
|
||||
}
|
||||
);
|
||||
const definedHeaderLp: HeaderDefine[] = [
|
||||
@@ -33,7 +38,7 @@ export function generateWiersze(faVat: Fa): Content {
|
||||
{ name: 'P_7', title: 'Nazwa towaru lub usługi', format: FormatTyp.Default, width: '*' },
|
||||
{ name: 'P_9A', title: 'Cena jedn. netto', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'P_9B', title: 'Cena jedn. brutto', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'P_8B', title: 'Ilość', format: FormatTyp.Right, width: 'auto' },
|
||||
{ name: 'P_8B', title: 'Ilość', format: FormatTyp.Number, width: 'auto' },
|
||||
{ name: 'P_8A', title: 'Miara', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'P_10', title: 'Rabat', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'P_12', title: 'Stawka podatku', format: FormatTyp.Default, width: 'auto' },
|
||||
|
||||
@@ -12,6 +12,8 @@ vi.mock('../../../shared/PDF-functions', () => ({
|
||||
formatText: vi.fn(),
|
||||
getContentTable: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
getValue: vi.fn(),
|
||||
getTStawkaPodatku: vi.fn()
|
||||
}));
|
||||
|
||||
describe(generateZamowienie.name, () => {
|
||||
|
||||
@@ -5,6 +5,8 @@ import {
|
||||
formatText,
|
||||
getContentTable,
|
||||
getTable,
|
||||
getTStawkaPodatku,
|
||||
getValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { Procedura, TRodzajFaktury } from '../../../shared/consts/const';
|
||||
@@ -29,6 +31,9 @@ export function generateZamowienie(
|
||||
if (!el.NrWierszaZam._text) {
|
||||
el.NrWierszaZam._text = (index + 1).toString();
|
||||
}
|
||||
if (getValue(el.P_12)) {
|
||||
el.P_12._text = getTStawkaPodatku(getValue(el.P_12) as string, 1);
|
||||
}
|
||||
return el;
|
||||
});
|
||||
const definedHeaderLp: HeaderDefine[] = [
|
||||
|
||||
@@ -8,6 +8,7 @@ vi.mock('../../../shared/PDF-functions', () => ({
|
||||
formatText: vi.fn((text: string) => ({ text })),
|
||||
getTable: vi.fn(() => []),
|
||||
hasValue: vi.fn((v) => !!v?._text),
|
||||
getValue: vi.fn((v) => v?._text || v),
|
||||
verticalSpacing: vi.fn((n: number) => ({ text: `space-${n}` })),
|
||||
generateColumns: vi.fn((left, right) => ({ columns: [left, right] })),
|
||||
}));
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
formatText,
|
||||
generateColumns,
|
||||
getTable,
|
||||
getValue,
|
||||
hasValue,
|
||||
verticalSpacing,
|
||||
} from '../../../shared/PDF-functions';
|
||||
@@ -169,6 +170,19 @@ export function generateDostawy(noweSrodkiTransportu: NoweSrodkiTransportu): Con
|
||||
} else if (anyP22D) {
|
||||
value.push('Dostawa dotyczy statków powietrznych, o których mowa w art. 2 pkt 10 lit. c ustawy');
|
||||
}
|
||||
|
||||
const transportProperties = [
|
||||
getValue(item.P_22BMK),
|
||||
getValue(item.P_22BMD),
|
||||
getValue(item.P_22BK),
|
||||
getValue(item.P_22BNR),
|
||||
getValue(item.P_22BRP),
|
||||
].filter((prop) => !!prop);
|
||||
|
||||
if (transportProperties.length) {
|
||||
value.push(transportProperties.join(', '));
|
||||
}
|
||||
|
||||
if (item.DetailsString?._text) {
|
||||
value.push(item.DetailsString._text);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export function generatePlatnosc(platnosc: Platnosc | undefined): Content {
|
||||
|
||||
if (platnosc.Zaplacono?._text === '1') {
|
||||
table.push(createLabelText('Informacja o płatności: ', 'Zapłacono'));
|
||||
table.push(createLabelText('Data zapłaty: ', platnosc.DataZaplaty));
|
||||
table.push(createLabelText('Data zapłaty: ', platnosc.DataZaplaty, FormatTyp.Date));
|
||||
} else if (platnosc.ZnacznikZaplatyCzesciowej?._text === '1') {
|
||||
table.push(createLabelText('Informacja o płatności: ', 'Zapłata częściowa'));
|
||||
} else {
|
||||
|
||||
@@ -36,8 +36,12 @@ export function generatePodmiot2Podmiot2K(podmiot2: Podmiot2, podmiot2K: Podmiot
|
||||
columnGap: 20,
|
||||
});
|
||||
}
|
||||
firstColumn = generateCorrectedContent(podmiot2K, 'Treść korygowana');
|
||||
secondColumn = generateCorrectedContent(podmiot2, 'Treść korygująca');
|
||||
|
||||
if(podmiot2K.Adres?.AdresL1?._text) {
|
||||
firstColumn = generateCorrectedContent(podmiot2K, 'Treść korygowana');
|
||||
secondColumn = generateCorrectedContent(podmiot2, 'Treść korygująca');
|
||||
}
|
||||
|
||||
if (podmiot2.AdresKoresp) {
|
||||
secondColumn.push(
|
||||
formatText('Adres do korespondencji', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
|
||||
@@ -140,7 +140,7 @@ describe(generatePodsumowanieStawekPodatkuVat.name, () => {
|
||||
expect(summary[0].taxRateString).toBe('23% lub 22%');
|
||||
expect(summary[1].taxRateString).toBe('8% lub 7%');
|
||||
expect(summary[2].taxRateString).toBe('5%');
|
||||
expect(summary[3].taxRateString).toBe('4% lub 3% lub oo');
|
||||
expect(summary[3].taxRateString).toBe('4% lub 3%');
|
||||
expect(summary[4].taxRateString).toBe('');
|
||||
expect(summary[5].taxRateString).toBe('0% - krajowe');
|
||||
expect(summary[6].taxRateString).toBe('0% - wdt');
|
||||
@@ -148,6 +148,7 @@ describe(generatePodsumowanieStawekPodatkuVat.name, () => {
|
||||
expect(summary[8].taxRateString).toBe('zwolnione z opodatkowania');
|
||||
expect(summary[9].taxRateString).toBe('np z wyłączeniem art. 100 ust 1 pkt 4 ustawy');
|
||||
expect(summary[10].taxRateString).toBe('np na podstawie art. 100 ust. 1 pkt 4 ustawy');
|
||||
expect(summary[11].taxRateString).toBe('odwrotne obciążenie');
|
||||
});
|
||||
|
||||
it('handles reverse charge and margin', () => {
|
||||
|
||||
@@ -173,7 +173,7 @@ export function getSummaryTaxRate(fa: Fa): TaxSummaryTypes[] {
|
||||
gross: (getNumberRounded(fa.P_13_4) + getNumberRounded(fa.P_14_4)).toFixed(2),
|
||||
tax: getNumberRounded(fa.P_14_4).toFixed(2),
|
||||
taxPLN: getNumberRounded(fa.P_14_4W).toFixed(2),
|
||||
taxRateString: '4% lub 3% lub oo',
|
||||
taxRateString: '4% lub 3%',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
@@ -217,8 +217,8 @@ export function getSummaryTaxRate(fa: Fa): TaxSummaryTypes[] {
|
||||
if (AnyP13_6_3Diff0) {
|
||||
summary.push({
|
||||
no,
|
||||
net: getNumberRounded(fa.P_13_6_2).toFixed(2),
|
||||
gross: getNumberRounded(fa.P_13_6_2).toFixed(2),
|
||||
net: getNumberRounded(fa.P_13_6_3).toFixed(2),
|
||||
gross: getNumberRounded(fa.P_13_6_3).toFixed(2),
|
||||
tax: '0.00',
|
||||
taxPLN: '',
|
||||
taxRateString: '0% - eksport',
|
||||
|
||||
@@ -82,7 +82,7 @@ describe(generateRabat.name, () => {
|
||||
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ name: 'NrWierszaFay', title: 'Lp.' }),
|
||||
expect.objectContaining({ name: 'NrWierszaFa', title: 'Lp.' }),
|
||||
expect.objectContaining({ name: 'P_7', title: 'Nazwa towaru lub usługi' }),
|
||||
expect.objectContaining({ name: 'P_8B', title: 'Ilość' }),
|
||||
expect.objectContaining({ name: 'P_8A', title: 'Miara' }),
|
||||
|
||||
@@ -18,7 +18,7 @@ export function generateRabat(invoice: Fa): Content[] {
|
||||
const faRows: Record<string, FP>[] = getTable(invoice!.FaWiersz);
|
||||
const result: Content[] = [];
|
||||
const definedHeader: HeaderDefine[] = [
|
||||
{ name: 'NrWierszaFay', title: 'Lp.', format: FormatTyp.Default },
|
||||
{ name: 'NrWierszaFa', title: 'Lp.', format: FormatTyp.Default },
|
||||
{ name: 'P_7', title: 'Nazwa towaru lub usługi', format: FormatTyp.Default },
|
||||
{ name: 'P_8B', title: 'Ilość', format: FormatTyp.Default },
|
||||
{ name: 'P_8A', title: 'Miara', format: FormatTyp.Default },
|
||||
|
||||
@@ -96,7 +96,11 @@ describe(generateSzczegoly.name, () => {
|
||||
|
||||
generateSzczegoly(data);
|
||||
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Data otrzymania zapłaty: ', data.P_6);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data otrzymania zapłaty: ',
|
||||
data.P_6,
|
||||
FormatTyp.Date
|
||||
);
|
||||
});
|
||||
|
||||
it('should use "Data otrzymania zapłaty" label for KOR_ZAL invoice', () => {
|
||||
@@ -107,7 +111,11 @@ describe(generateSzczegoly.name, () => {
|
||||
|
||||
generateSzczegoly(data);
|
||||
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Data otrzymania zapłaty: ', data.P_6);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data otrzymania zapłaty: ',
|
||||
data.P_6,
|
||||
FormatTyp.Date
|
||||
);
|
||||
});
|
||||
|
||||
it('should use "Data dokonania lub zakończenia dostawy" label for other invoice types', () => {
|
||||
@@ -120,7 +128,8 @@ describe(generateSzczegoly.name, () => {
|
||||
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data dokonania lub zakończenia dostawy towarów lub wykonania usługi: ',
|
||||
data.P_6
|
||||
data.P_6,
|
||||
FormatTyp.Date
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -386,7 +395,8 @@ describe(generateSzczegoly.name, () => {
|
||||
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data wystawienia, z zastrzeżeniem art. 106na ust. 1 ustawy: ',
|
||||
mockFaVat.P_1
|
||||
mockFaVat.P_1,
|
||||
FormatTyp.Date
|
||||
);
|
||||
});
|
||||
|
||||
@@ -546,7 +556,7 @@ describe(generateSzczegoly.name, () => {
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: 'NrKSeFFaZaliczkowej',
|
||||
name: 'NrFaZaliczkowej',
|
||||
title: 'Numery wcześniejszych faktur zaliczkowych',
|
||||
}),
|
||||
]),
|
||||
|
||||
@@ -74,10 +74,14 @@ export function generateSzczegoly(faVat: Fa): Content[] {
|
||||
const tpLabel2: Content[] = [];
|
||||
|
||||
const forColumns: Content[][] = [
|
||||
createLabelText('Data wystawienia, z zastrzeżeniem art. 106na ust. 1 ustawy: ', faVat.P_1),
|
||||
createLabelText(
|
||||
'Data wystawienia, z zastrzeżeniem art. 106na ust. 1 ustawy: ',
|
||||
faVat.P_1,
|
||||
FormatTyp.Date
|
||||
),
|
||||
createLabelText('Miejsce wystawienia: ', faVat.P_1M),
|
||||
createLabelText('Okres, którego dotyczy rabat: ', faVat.OkresFaKorygowanej),
|
||||
createLabelText(LabelP_6, faVat.P_6),
|
||||
createLabelText(LabelP_6, faVat.P_6, FormatTyp.Date),
|
||||
P_6Scope,
|
||||
cenyLabel1,
|
||||
cenyLabel2,
|
||||
@@ -163,11 +167,22 @@ function generateFakturaZaliczkowa(fakturaZaliczkowaData: ObjectKeysOfFP[] | und
|
||||
return [];
|
||||
}
|
||||
const fakturaZaliczkowa = getTable(fakturaZaliczkowaData) as unknown as FA2FakturaZaliczkowaData[];
|
||||
const fakturaZaliczkowaMapped = fakturaZaliczkowa.map(item => {
|
||||
const fp =
|
||||
(
|
||||
'NrFaZaliczkowej' in item && item.NrFaZaliczkowej
|
||||
) ? item.NrFaZaliczkowej : ('NrKSeFFaZaliczkowej' in item ? item.NrKSeFFaZaliczkowej : undefined );
|
||||
|
||||
return{
|
||||
...item,
|
||||
NrFaZaliczkowej : fp ?? { _text: ''},
|
||||
};
|
||||
})
|
||||
const table: Content[] = [];
|
||||
|
||||
const fakturaZaliczkowaHeader: HeaderDefine[] = [
|
||||
{
|
||||
name: 'NrKSeFFaZaliczkowej',
|
||||
name: 'NrFaZaliczkowej',
|
||||
title: 'Numery wcześniejszych faktur zaliczkowych',
|
||||
format: FormatTyp.Default,
|
||||
},
|
||||
@@ -175,7 +190,7 @@ function generateFakturaZaliczkowa(fakturaZaliczkowaData: ObjectKeysOfFP[] | und
|
||||
|
||||
const tableFakturaZaliczkowa: TableWithFields = getContentTable<(typeof fakturaZaliczkowa)[0]>(
|
||||
fakturaZaliczkowaHeader,
|
||||
fakturaZaliczkowa,
|
||||
fakturaZaliczkowaMapped,
|
||||
'auto',
|
||||
[0, 4, 0, 0]
|
||||
);
|
||||
|
||||
@@ -13,6 +13,7 @@ vi.mock('../../../shared/PDF-functions', () => ({
|
||||
getContentTable: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
getValue: vi.fn(),
|
||||
getTStawkaPodatku: vi.fn()
|
||||
}));
|
||||
|
||||
describe(generateWiersze.name, () => {
|
||||
@@ -27,6 +28,7 @@ describe(generateWiersze.name, () => {
|
||||
P_7: { _text: 'Product 1' },
|
||||
P_9A: { _text: '100' },
|
||||
P_8B: { _text: '2' },
|
||||
P_12: { _text: '23' },
|
||||
},
|
||||
],
|
||||
KodWaluty: { _text: 'PLN' },
|
||||
@@ -106,7 +108,7 @@ describe(generateWiersze.name, () => {
|
||||
});
|
||||
|
||||
it('should display "brutto" when P_11 is not in fieldsWithValue', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' }, P_12: {_text: '23'} }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
@@ -148,7 +150,7 @@ describe(generateWiersze.name, () => {
|
||||
});
|
||||
|
||||
it('should generate two tables when fieldsWithValue.length > 8', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' }, P_12: {_text: '23'} }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable)
|
||||
.mockReturnValueOnce({
|
||||
@@ -175,7 +177,7 @@ describe(generateWiersze.name, () => {
|
||||
});
|
||||
|
||||
it('should not add second table if it has only 1 field with value', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' }, P_12: {_text: '23'} }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable)
|
||||
.mockReturnValueOnce({
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
formatText,
|
||||
getContentTable,
|
||||
getTable,
|
||||
getTStawkaPodatku,
|
||||
getValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
@@ -13,15 +14,19 @@ import { TRodzajFaktury } from '../../../shared/consts/const';
|
||||
import { Fa, FP } from '../../types/fa2.types';
|
||||
import FormatTyp, { Position } from '../../../shared/enums/common.enum';
|
||||
import { TableWithFields } from '../../types/fa1-additional-types';
|
||||
import { shouldAddMarza } from '../common/Wiersze';
|
||||
import { addMarza } from '../common/Wiersze';
|
||||
|
||||
export function generateWiersze(faVat: Fa): Content {
|
||||
const table: Content[] = [];
|
||||
const rodzajFaktury: string | number | undefined = getValue(faVat.RodzajFaktury);
|
||||
const isP_PMarzy: boolean = Boolean(Number(getValue(faVat.Adnotacje?.PMarzy?.P_PMarzy)));
|
||||
const isP_PMarzy = Boolean(Number(getValue(faVat.Adnotacje?.PMarzy?.P_PMarzy)));
|
||||
const faWiersze: Record<string, FP>[] = getTable(faVat.FaWiersz).map((wiersz) => {
|
||||
const marza: Record<string, FP> = shouldAddMarza(rodzajFaktury, isP_PMarzy, wiersz)!;
|
||||
return marza ? { ...wiersz, ...marza } : wiersz;
|
||||
const marza: Record<string, FP> = addMarza(rodzajFaktury, isP_PMarzy, wiersz)!;
|
||||
|
||||
if (getValue(wiersz.P_12)) {
|
||||
wiersz.P_12._text = getTStawkaPodatku(getValue(wiersz.P_12) as string, 2);
|
||||
}
|
||||
return { ...wiersz, ...marza };
|
||||
});
|
||||
|
||||
const definedHeaderLp: HeaderDefine[] = [
|
||||
@@ -32,7 +37,7 @@ export function generateWiersze(faVat: Fa): Content {
|
||||
{ name: 'P_7', title: 'Nazwa towaru lub usługi', format: FormatTyp.Default, width: '*' },
|
||||
{ name: 'P_9A', title: 'Cena jedn. netto', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'P_9B', title: 'Cena jedn. brutto', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'P_8B', title: 'Ilość', format: FormatTyp.Right, width: 'auto' },
|
||||
{ name: 'P_8B', title: 'Ilość', format: FormatTyp.Number, width: 'auto' },
|
||||
{ name: 'P_8A', title: 'Miara', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'P_10', title: 'Rabat', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'P_12', title: 'Stawka podatku', format: FormatTyp.Default, width: 'auto' },
|
||||
|
||||
@@ -12,6 +12,8 @@ vi.mock('../../../shared/PDF-functions', () => ({
|
||||
formatText: vi.fn(),
|
||||
getContentTable: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
getValue: vi.fn(),
|
||||
getTStawkaPodatku: vi.fn()
|
||||
}));
|
||||
|
||||
describe(generateZamowienie.name, () => {
|
||||
|
||||
@@ -5,6 +5,8 @@ import {
|
||||
formatText,
|
||||
getContentTable,
|
||||
getTable,
|
||||
getTStawkaPodatku,
|
||||
getValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { TRodzajFaktury } from '../../../shared/consts/const';
|
||||
@@ -29,6 +31,9 @@ export function generateZamowienie(
|
||||
if (!el.NrWierszaZam._text) {
|
||||
el.NrWierszaZam._text = (index + 1).toString();
|
||||
}
|
||||
if (getValue(el.P_12)) {
|
||||
el.P_12._text = getTStawkaPodatku(getValue(el.P_12) as string, 2);
|
||||
}
|
||||
return el;
|
||||
});
|
||||
const definedHeaderLp: HeaderDefine[] = [
|
||||
@@ -56,6 +61,7 @@ export function generateZamowienie(
|
||||
{ name: 'P_11NettoZ', title: 'Wartość sprzedaży netto', format: formatAbs, width: 'auto' },
|
||||
{ name: 'P_11VatZ', title: 'Kwota podatku', format: formatAbs, width: 'auto' },
|
||||
];
|
||||
|
||||
const definedHeader2: HeaderDefine[] = [
|
||||
{ name: 'UU_IDZ', title: 'Numer umowy / Zamów.', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'GTINZ', title: 'GTIN', format: FormatTyp.Default, width: 'auto' },
|
||||
|
||||
@@ -8,6 +8,7 @@ vi.mock('../../../shared/PDF-functions', () => ({
|
||||
formatText: vi.fn((text: string) => ({ text })),
|
||||
getTable: vi.fn(() => []),
|
||||
hasValue: vi.fn((v) => !!v?._text),
|
||||
getValue: vi.fn((v) => v?._text || v),
|
||||
verticalSpacing: vi.fn((n: number) => ({ text: `space-${n}` })),
|
||||
generateColumns: vi.fn((left, right) => ({ columns: [left, right] })),
|
||||
}));
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
formatText,
|
||||
generateColumns,
|
||||
getTable,
|
||||
getValue,
|
||||
hasValue,
|
||||
verticalSpacing,
|
||||
} from '../../../shared/PDF-functions';
|
||||
@@ -199,6 +200,19 @@ export function generateDostawy(noweSrodkiTransportu: NoweSrodkiTransportu): Con
|
||||
} else if (anyP22D) {
|
||||
value.push('Dostawa dotyczy statków powietrznych, o których mowa w art. 2 pkt 10 lit. c ustawy');
|
||||
}
|
||||
|
||||
const transportProperties = [
|
||||
getValue(item.P_22BMK),
|
||||
getValue(item.P_22BMD),
|
||||
getValue(item.P_22BK),
|
||||
getValue(item.P_22BNR),
|
||||
getValue(item.P_22BRP),
|
||||
].filter((prop) => !!prop);
|
||||
|
||||
if (transportProperties.length) {
|
||||
value.push(transportProperties.join(', '));
|
||||
}
|
||||
|
||||
if (item.DetailsString?._text) {
|
||||
value.push(item.DetailsString._text);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ export function generatePlatnosc(platnosc: Platnosc | undefined): Content {
|
||||
// TODO: Add to FA2 and FA1? (KSEF20-15289)
|
||||
if (getValue(platnosc.Zaplacono) === '1') {
|
||||
table.push(createLabelText('Informacja o płatności: ', 'Zapłacono'));
|
||||
table.push(createLabelText('Data zapłaty: ', platnosc.DataZaplaty));
|
||||
table.push(createLabelText('Data zapłaty: ', platnosc.DataZaplaty, FormatTyp.Date));
|
||||
} else if (
|
||||
getValue(platnosc.ZnacznikZaplatyCzesciowej) === '1' ||
|
||||
getValue(platnosc.ZnacznikZaplatyCzesciowej) === '2'
|
||||
|
||||
@@ -38,8 +38,11 @@ export function generatePodmiot2Podmiot2K(podmiot2: Podmiot2, podmiot2K: Podmiot
|
||||
columnGap: 20,
|
||||
});
|
||||
}
|
||||
firstColumn = generateCorrectedContent(podmiot2K, 'Treść korygowana');
|
||||
secondColumn = generateCorrectedContent(podmiot2, 'Treść korygująca');
|
||||
|
||||
if(podmiot2K.Adres?.AdresL1?._text){
|
||||
firstColumn = generateCorrectedContent(podmiot2K, 'Treść korygowana');
|
||||
secondColumn = generateCorrectedContent(podmiot2, 'Treść korygująca');
|
||||
}
|
||||
|
||||
if (podmiot2.AdresKoresp) {
|
||||
secondColumn.push(
|
||||
|
||||
@@ -139,14 +139,15 @@ describe(generatePodsumowanieStawekPodatkuVat.name, () => {
|
||||
expect(summary[0].taxRateString).toBe('23% lub 22%');
|
||||
expect(summary[1].taxRateString).toBe('8% lub 7%');
|
||||
expect(summary[2].taxRateString).toBe('5%');
|
||||
expect(summary[3].taxRateString).toBe('4% lub 3% lub oo');
|
||||
expect(summary[3].taxRateString).toBe('4% lub 3%');
|
||||
expect(summary[4].taxRateString).toBe('');
|
||||
expect(summary[5].taxRateString).toBe('0% - krajowe');
|
||||
expect(summary[6].taxRateString).toBe('0% - wdt');
|
||||
expect(summary[7].taxRateString).toBe('0% - eksport');
|
||||
expect(summary[8].taxRateString).toBe('zwolnione z opodatkowania');
|
||||
expect(summary[5].taxRateString).toBe('0% w przypadku sprzedaży towarów i świadczenia usług na terytorium kraju (z wyłączeniem WDT i eksportu)');
|
||||
expect(summary[6].taxRateString).toBe('0% w przypadku wewnątrzwspólnotowej dostawy towarów (WDT)');
|
||||
expect(summary[7].taxRateString).toBe('0% w przypadku eksportu towarów');
|
||||
expect(summary[8].taxRateString).toBe('zwolnione od podatku');
|
||||
expect(summary[9].taxRateString).toBe('np z wyłączeniem art. 100 ust 1 pkt 4 ustawy');
|
||||
expect(summary[10].taxRateString).toBe('np na podstawie art. 100 ust. 1 pkt 4 ustawy');
|
||||
expect(summary[11].taxRateString).toBe('odwrotne obciążenie');
|
||||
});
|
||||
|
||||
it('handles reverse charge and margin', () => {
|
||||
|
||||
@@ -177,7 +177,7 @@ export function getSummaryTaxRate(fa: Fa): TaxSummaryTypes[] {
|
||||
gross: (getNumberRounded(fa.P_13_4) + getNumberRounded(fa.P_14_4)).toFixed(2),
|
||||
tax: getNumberRounded(fa.P_14_4).toFixed(2),
|
||||
taxPLN: getNumberRounded(fa.P_14_4W).toFixed(2),
|
||||
taxRateString: '4% lub 3% lub oo',
|
||||
taxRateString: '4% lub 3%',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
@@ -201,7 +201,7 @@ export function getSummaryTaxRate(fa: Fa): TaxSummaryTypes[] {
|
||||
gross: getNumberRounded(fa.P_13_6_1).toFixed(2),
|
||||
tax: '0.00',
|
||||
taxPLN: '',
|
||||
taxRateString: '0% - krajowe',
|
||||
taxRateString: '0% w przypadku sprzedaży towarów i świadczenia usług na terytorium kraju (z wyłączeniem WDT i eksportu)',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
@@ -213,7 +213,7 @@ export function getSummaryTaxRate(fa: Fa): TaxSummaryTypes[] {
|
||||
gross: getNumberRounded(fa.P_13_6_2).toFixed(2),
|
||||
tax: '0.00',
|
||||
taxPLN: '',
|
||||
taxRateString: '0% - wdt',
|
||||
taxRateString: '0% w przypadku wewnątrzwspólnotowej dostawy towarów (WDT)',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
@@ -221,11 +221,11 @@ export function getSummaryTaxRate(fa: Fa): TaxSummaryTypes[] {
|
||||
if (AnyP13_6_3Diff0) {
|
||||
summary.push({
|
||||
no,
|
||||
net: getNumberRounded(fa.P_13_6_2).toFixed(2),
|
||||
gross: getNumberRounded(fa.P_13_6_2).toFixed(2),
|
||||
net: getNumberRounded(fa.P_13_6_3).toFixed(2),
|
||||
gross: getNumberRounded(fa.P_13_6_3).toFixed(2),
|
||||
tax: '0.00',
|
||||
taxPLN: '',
|
||||
taxRateString: '0% - eksport',
|
||||
taxRateString: '0% w przypadku eksportu towarów',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
@@ -237,7 +237,7 @@ export function getSummaryTaxRate(fa: Fa): TaxSummaryTypes[] {
|
||||
gross: getNumberRounded(fa.P_13_7).toFixed(2),
|
||||
tax: '0.00',
|
||||
taxPLN: '',
|
||||
taxRateString: 'zwolnione z opodatkowania',
|
||||
taxRateString: 'zwolnione od podatku',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ describe(generateRabat.name, () => {
|
||||
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ name: 'NrWierszaFay', title: 'Lp.' }),
|
||||
expect.objectContaining({ name: 'NrWierszaFa', title: 'Lp.' }),
|
||||
expect.objectContaining({ name: 'P_7', title: 'Nazwa towaru lub usługi' }),
|
||||
expect.objectContaining({ name: 'P_8B', title: 'Ilość' }),
|
||||
expect.objectContaining({ name: 'P_8A', title: 'Miara' }),
|
||||
|
||||
@@ -16,12 +16,13 @@ export function generateRabat(invoice: Fa): Content[] {
|
||||
const faRows = getTable(invoice!.FaWiersz);
|
||||
const result: Content[] = [];
|
||||
const definedHeader: HeaderDefine[] = [
|
||||
{ name: 'NrWierszaFay', title: 'Lp.', format: FormatTyp.Default },
|
||||
{ name: 'NrWierszaFa', title: 'Lp.', format: FormatTyp.Default },
|
||||
{ name: 'P_7', title: 'Nazwa towaru lub usługi', format: FormatTyp.Default },
|
||||
{ name: 'P_8B', title: 'Ilość', format: FormatTyp.Default },
|
||||
{ name: 'P_8A', title: 'Miara', format: FormatTyp.Default },
|
||||
];
|
||||
const tabRabat = getContentTable<(typeof faRows)[0]>(definedHeader, faRows, '*');
|
||||
|
||||
const isNrWierszaFa = tabRabat.fieldsWithValue.includes('NrWierszaFa');
|
||||
|
||||
result.push(
|
||||
|
||||
@@ -96,7 +96,11 @@ describe(generateSzczegoly.name, () => {
|
||||
|
||||
generateSzczegoly(data);
|
||||
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Data otrzymania zapłaty: ', data.P_6);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data otrzymania zapłaty: ',
|
||||
data.P_6,
|
||||
FormatTyp.Date
|
||||
);
|
||||
});
|
||||
|
||||
it('should use "Data otrzymania zapłaty" label for KOR_ZAL invoice', () => {
|
||||
@@ -107,7 +111,11 @@ describe(generateSzczegoly.name, () => {
|
||||
|
||||
generateSzczegoly(data);
|
||||
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Data otrzymania zapłaty: ', data.P_6);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data otrzymania zapłaty: ',
|
||||
data.P_6,
|
||||
FormatTyp.Date
|
||||
);
|
||||
});
|
||||
|
||||
it('should use "Data dokonania lub zakończenia dostawy" label for other invoice types', () => {
|
||||
@@ -120,7 +128,8 @@ describe(generateSzczegoly.name, () => {
|
||||
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data dokonania lub zakończenia dostawy towarów lub wykonania usługi: ',
|
||||
data.P_6
|
||||
data.P_6,
|
||||
FormatTyp.Date
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -386,7 +395,8 @@ describe(generateSzczegoly.name, () => {
|
||||
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data wystawienia, z zastrzeżeniem art. 106na ust. 1 ustawy: ',
|
||||
mockFaVat.P_1
|
||||
mockFaVat.P_1,
|
||||
FormatTyp.Date
|
||||
);
|
||||
});
|
||||
|
||||
@@ -546,7 +556,7 @@ describe(generateSzczegoly.name, () => {
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: 'NrKSeFFaZaliczkowej',
|
||||
name: 'NrFaZaliczkowej',
|
||||
title: 'Numery wcześniejszych faktur zaliczkowych',
|
||||
}),
|
||||
]),
|
||||
|
||||
@@ -71,10 +71,14 @@ export function generateSzczegoly(faVat: Fa): Content[] {
|
||||
const tpLabel2: Content[] = [];
|
||||
|
||||
const forColumns = [
|
||||
createLabelText('Data wystawienia, z zastrzeżeniem art. 106na ust. 1 ustawy: ', faVat.P_1),
|
||||
createLabelText(
|
||||
'Data wystawienia, z zastrzeżeniem art. 106na ust. 1 ustawy: ',
|
||||
faVat.P_1,
|
||||
FormatTyp.Date
|
||||
),
|
||||
createLabelText('Miejsce wystawienia: ', faVat.P_1M),
|
||||
createLabelText('Okres, którego dotyczy rabat: ', faVat.OkresFaKorygowanej),
|
||||
createLabelText(LabelP_6, faVat.P_6),
|
||||
createLabelText(LabelP_6, faVat.P_6, FormatTyp.Date),
|
||||
P_6Scope,
|
||||
cenyLabel1,
|
||||
cenyLabel2,
|
||||
@@ -160,11 +164,22 @@ function generateFakturaZaliczkowa(fakturaZaliczkowaData: ObjectKeysOfFP[] | und
|
||||
return [];
|
||||
}
|
||||
const fakturaZaliczkowa = getTable(fakturaZaliczkowaData) as unknown as FA3FakturaZaliczkowaData[];
|
||||
const fakturaZaliczkowaMapped = fakturaZaliczkowa.map(item => {
|
||||
const fp =
|
||||
(
|
||||
'NrFaZaliczkowej' in item && item.NrFaZaliczkowej
|
||||
) ? item.NrFaZaliczkowej : ('NrKSeFFaZaliczkowej' in item ? item.NrKSeFFaZaliczkowej : undefined );
|
||||
|
||||
return{
|
||||
...item,
|
||||
NrFaZaliczkowej : fp ?? { _text: ''},
|
||||
};
|
||||
})
|
||||
const table: Content[] = [];
|
||||
|
||||
const fakturaZaliczkowaHeader: HeaderDefine[] = [
|
||||
{
|
||||
name: 'NrKSeFFaZaliczkowej',
|
||||
name: 'NrFaZaliczkowej',
|
||||
title: 'Numery wcześniejszych faktur zaliczkowych',
|
||||
format: FormatTyp.Default,
|
||||
},
|
||||
@@ -172,7 +187,7 @@ function generateFakturaZaliczkowa(fakturaZaliczkowaData: ObjectKeysOfFP[] | und
|
||||
|
||||
const tableFakturaZaliczkowa = getContentTable<(typeof fakturaZaliczkowa)[0]>(
|
||||
fakturaZaliczkowaHeader,
|
||||
fakturaZaliczkowa,
|
||||
fakturaZaliczkowaMapped,
|
||||
'auto',
|
||||
[0, 4, 0, 0]
|
||||
);
|
||||
|
||||
@@ -12,7 +12,8 @@ vi.mock('../../../shared/PDF-functions', () => ({
|
||||
formatText: vi.fn(),
|
||||
getContentTable: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
getValue: vi.fn(),
|
||||
getValue: vi.fn((v) => v?._text || v),
|
||||
getTStawkaPodatku: vi.fn()
|
||||
}));
|
||||
|
||||
describe(generateWiersze.name, () => {
|
||||
@@ -27,6 +28,7 @@ describe(generateWiersze.name, () => {
|
||||
P_7: { _text: 'Product 1' },
|
||||
P_9A: { _text: '100' },
|
||||
P_8B: { _text: '2' },
|
||||
P_12: { _text: '23' },
|
||||
},
|
||||
],
|
||||
KodWaluty: { _text: 'PLN' },
|
||||
@@ -59,6 +61,8 @@ describe(generateWiersze.name, () => {
|
||||
vi.mocked(PDFFunctions.createHeader).mockReturnValue(['Header'] as any);
|
||||
vi.mocked(PDFFunctions.createSection).mockReturnValue({ section: 'content' } as any);
|
||||
vi.mocked(PDFFunctions.createLabelTextArray).mockReturnValue(['Label', 'Value'] as any);
|
||||
vi.mocked(PDFFunctions.getTStawkaPodatku).mockReturnValue('0' as any);
|
||||
|
||||
};
|
||||
|
||||
describe('when no invoice lines exist', () => {
|
||||
@@ -106,11 +110,11 @@ describe(generateWiersze.name, () => {
|
||||
});
|
||||
|
||||
it('should display "brutto" when P_11 is not in fieldsWithValue', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' }, P_12: {_text: '23'} }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['P_11A', 'P_7'],
|
||||
fieldsWithValue: ['P_11A', 'P_7', 'P12'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getValue).mockReturnValue('0');
|
||||
@@ -148,7 +152,7 @@ describe(generateWiersze.name, () => {
|
||||
});
|
||||
|
||||
it('should generate two tables when fieldsWithValue.length > 8', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' }, P_12: {_text: '23'} }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable)
|
||||
.mockReturnValueOnce({
|
||||
@@ -175,7 +179,7 @@ describe(generateWiersze.name, () => {
|
||||
});
|
||||
|
||||
it('should not add second table if it has only 1 field with value', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' }, P_12: {_text: '23'} }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable)
|
||||
.mockReturnValueOnce({
|
||||
|
||||
@@ -6,22 +6,27 @@ import {
|
||||
formatText,
|
||||
getContentTable,
|
||||
getTable,
|
||||
getTStawkaPodatku,
|
||||
getValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { TRodzajFaktury } from '../../../shared/consts/const';
|
||||
import { Fa, FP } from '../../types/fa3.types';
|
||||
import FormatTyp, { Position } from '../../../shared/enums/common.enum';
|
||||
import { shouldAddMarza } from '../common/Wiersze';
|
||||
import { addMarza } from '../common/Wiersze';
|
||||
|
||||
export function generateWiersze(faVat: Fa): Content {
|
||||
const table: Content[] = [];
|
||||
const rodzajFaktury: string | number | undefined = getValue(faVat.RodzajFaktury);
|
||||
const isP_PMarzy: boolean = Boolean(Number(getValue(faVat.Adnotacje?.PMarzy?.P_PMarzy)));
|
||||
const isP_PMarzy = Boolean(Number(getValue(faVat.Adnotacje?.PMarzy?.P_PMarzy)));
|
||||
const faWiersze: Record<string, FP>[] = getTable(faVat.FaWiersz).map(
|
||||
(wiersz: Record<string, FP>): Record<string, FP> => {
|
||||
const marza: Record<string, FP> = shouldAddMarza(rodzajFaktury, isP_PMarzy, wiersz)!;
|
||||
return marza ? { ...wiersz, ...marza } : wiersz;
|
||||
const marza: Record<string, FP> = addMarza(rodzajFaktury, isP_PMarzy, wiersz)!;
|
||||
|
||||
if (getValue(wiersz.P_12)) {
|
||||
wiersz.P_12._text = getTStawkaPodatku(getValue(wiersz.P_12) as string, 3);
|
||||
}
|
||||
return { ...wiersz, ...marza };
|
||||
}
|
||||
);
|
||||
const definedHeaderLp: HeaderDefine[] = [
|
||||
@@ -32,7 +37,7 @@ export function generateWiersze(faVat: Fa): Content {
|
||||
{ name: 'P_7', title: 'Nazwa towaru lub usługi', format: FormatTyp.Default, width: '*' },
|
||||
{ name: 'P_9A', title: 'Cena jedn. netto', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'P_9B', title: 'Cena jedn. brutto', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'P_8B', title: 'Ilość', format: FormatTyp.Right, width: 'auto' },
|
||||
{ name: 'P_8B', title: 'Ilość', format: FormatTyp.Number, width: 'auto' },
|
||||
{ name: 'P_8A', title: 'Miara', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'P_10', title: 'Rabat', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'P_12', title: 'Stawka podatku', format: FormatTyp.Default, width: 'auto' },
|
||||
|
||||
@@ -12,6 +12,8 @@ vi.mock('../../../shared/PDF-functions', () => ({
|
||||
formatText: vi.fn(),
|
||||
getContentTable: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
getValue: vi.fn(),
|
||||
getTStawkaPodatku: vi.fn()
|
||||
}));
|
||||
|
||||
describe(generateZamowienie.name, () => {
|
||||
|
||||
@@ -5,6 +5,8 @@ import {
|
||||
formatText,
|
||||
getContentTable,
|
||||
getTable,
|
||||
getTStawkaPodatku,
|
||||
getValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { TRodzajFaktury } from '../../../shared/consts/const';
|
||||
@@ -28,6 +30,9 @@ export function generateZamowienie(
|
||||
if (!el.NrWierszaZam._text) {
|
||||
el.NrWierszaZam._text = (index + 1).toString();
|
||||
}
|
||||
if (getValue(el.P_12Z)) {
|
||||
el.P_12Z._text = getTStawkaPodatku(getValue(el.P_12Z) as string, 3);
|
||||
}
|
||||
return el;
|
||||
});
|
||||
const definedHeaderLp: HeaderDefine[] = [
|
||||
|
||||
123
src/lib-public/generators/UPO4_3/Dokumenty.spec.ts
Normal file
123
src/lib-public/generators/UPO4_3/Dokumenty.spec.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import * as PDFFunctions from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { Potwierdzenie } from '../../types/upo-v4_3.types';
|
||||
import { generateDokumentUPO } from './Dokumenty';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
formatText: vi.fn(),
|
||||
generateLine: vi.fn(),
|
||||
getContentTable: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
getValue: vi.fn(),
|
||||
hasValue: vi.fn(),
|
||||
verticalSpacing: vi.fn(),
|
||||
}));
|
||||
|
||||
describe(generateDokumentUPO.name, () => {
|
||||
let mockPotwierdzenie: Potwierdzenie;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
mockPotwierdzenie = {
|
||||
NumerReferencyjnySesji: { _text: 'NR123' },
|
||||
OpisPotwierdzenia: {
|
||||
Strona: { _text: '1' },
|
||||
LiczbaStron: { _text: '2' },
|
||||
ZakresDokumentowOd: { _text: 'FA001' },
|
||||
ZakresDokumentowDo: { _text: 'FA002' },
|
||||
CalkowitaLiczbaDokumentow: { _text: '2' },
|
||||
},
|
||||
Uwierzytelnienie: {
|
||||
IdKontekstu: {
|
||||
NIP: { _text: '1234567890' },
|
||||
},
|
||||
SkrotDokumentuUwierzytelniajacego: { _text: 'ABC123' },
|
||||
},
|
||||
NazwaStrukturyLogicznej: { _text: 'XSD' },
|
||||
KodFormularza: { _text: 'K123' },
|
||||
Dokument: [
|
||||
{
|
||||
NumerKSeFDokumentu: 'D001',
|
||||
NumerFaktury: 'F001',
|
||||
NipSprzedawcy: '123',
|
||||
DataWystawieniaFaktury: '2024-01-01',
|
||||
DataPrzeslaniaDokumentu: '2024-01-02',
|
||||
DataNadaniaNumeruKSeF: '2024-01-03',
|
||||
SkrotDokumentu: 'XYZ',
|
||||
},
|
||||
],
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue(mockPotwierdzenie.Dokument as any);
|
||||
vi.mocked(PDFFunctions.hasValue).mockReturnValue(true);
|
||||
vi.mocked(PDFFunctions.formatText).mockImplementation((text) => text as any);
|
||||
vi.mocked(PDFFunctions.generateLine).mockReturnValue('line' as any);
|
||||
vi.mocked(PDFFunctions.verticalSpacing).mockImplementation((val) => `space${val}` as any);
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: 'tableContent',
|
||||
fieldsWithValue: [],
|
||||
} as any);
|
||||
vi.mocked(PDFFunctions.getValue).mockImplementation((val: any) => val?._text);
|
||||
});
|
||||
|
||||
it('should generate basic UPO structure', () => {
|
||||
const result = generateDokumentUPO(mockPotwierdzenie);
|
||||
|
||||
expect(result[0]).toBe('space4');
|
||||
expect(result[1]).toBe('line');
|
||||
expect(result[2]).toBe('space8');
|
||||
expect(result[3]).toBe('Urzędowe poświadczenie odbioru dokumentu elektronicznego KSeF');
|
||||
expect(result[4]).toBe('space8');
|
||||
});
|
||||
|
||||
it('should include all UPO fields when hasValue returns true', () => {
|
||||
generateDokumentUPO(mockPotwierdzenie);
|
||||
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(
|
||||
'Numer referencyjny sesji: ',
|
||||
FormatTyp.GrayBoldTitle
|
||||
);
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith('Strona dokumentu UPO: ', FormatTyp.GrayBoldTitle);
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(
|
||||
'Całkowita liczba stron dokumentu UPO: ',
|
||||
FormatTyp.GrayBoldTitle
|
||||
);
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith('Zakres dokumentów od: ', FormatTyp.GrayBoldTitle);
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith('Zakres dokumentów do: ', FormatTyp.GrayBoldTitle);
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(
|
||||
'Całkowita liczba dokumentów: ',
|
||||
FormatTyp.GrayBoldTitle
|
||||
);
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith('Typ kontekstu: ', FormatTyp.GrayBoldTitle);
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(
|
||||
'Identyfikator kontekstu uwierzytelnienia: ',
|
||||
FormatTyp.GrayBoldTitle
|
||||
);
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(
|
||||
'Skrót dokumentu uwierzytelniającego: ',
|
||||
FormatTyp.GrayBoldTitle
|
||||
);
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(
|
||||
'Nazwa pliku XSD struktury logicznej dotycząca przesłanego dokumentu:',
|
||||
FormatTyp.GrayBoldTitle
|
||||
);
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(
|
||||
'Kod formularza przedłożonego dokumentu elektronicznego:',
|
||||
FormatTyp.GrayBoldTitle
|
||||
);
|
||||
});
|
||||
|
||||
it('should not add document table if getContentTable.content is null', () => {
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({ content: null, fieldsWithValue: [] });
|
||||
const result = generateDokumentUPO(mockPotwierdzenie);
|
||||
|
||||
expect(result).not.toContain('null');
|
||||
});
|
||||
|
||||
it('should call getTable with Dokument', () => {
|
||||
generateDokumentUPO(mockPotwierdzenie);
|
||||
expect(PDFFunctions.getTable).toHaveBeenCalledWith(mockPotwierdzenie.Dokument);
|
||||
});
|
||||
});
|
||||
183
src/lib-public/generators/UPO4_3/Dokumenty.ts
Normal file
183
src/lib-public/generators/UPO4_3/Dokumenty.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
formatText,
|
||||
generateLine,
|
||||
getContentTable,
|
||||
getTable,
|
||||
getValue,
|
||||
hasValue,
|
||||
verticalSpacing,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { FormContentState } from '../../../shared/types/additional-data.types';
|
||||
import { DEFAULT_TABLE_LAYOUT } from '../../../shared/consts/const';
|
||||
import { Dokument, IDKontekstu, Potwierdzenie } from '../../types/upo-v4_3.types';
|
||||
|
||||
export function generateDokumentUPO(potwierdzenie: Potwierdzenie): Content[] {
|
||||
const dokumenty: Dokument[] = getTable(potwierdzenie.Dokument);
|
||||
|
||||
const result: Content[] = [];
|
||||
const table: Content[] = [];
|
||||
|
||||
result.push(verticalSpacing(4));
|
||||
result.push(generateLine());
|
||||
result.push(verticalSpacing(8));
|
||||
result.push(
|
||||
formatText('Urzędowe poświadczenie odbioru dokumentu elektronicznego KSeF', FormatTyp.HeaderPosition)
|
||||
);
|
||||
result.push(verticalSpacing(8));
|
||||
if (hasValue(potwierdzenie.NumerReferencyjnySesji)) {
|
||||
table.push([
|
||||
formatText('Numer referencyjny sesji: ', FormatTyp.GrayBoldTitle),
|
||||
formatText(potwierdzenie.NumerReferencyjnySesji?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(potwierdzenie.OpisPotwierdzenia?.Strona)) {
|
||||
table.push([
|
||||
formatText('Strona dokumentu UPO: ', FormatTyp.GrayBoldTitle),
|
||||
formatText(potwierdzenie.OpisPotwierdzenia?.Strona?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(potwierdzenie.OpisPotwierdzenia?.LiczbaStron)) {
|
||||
table.push([
|
||||
formatText('Całkowita liczba stron dokumentu UPO: ', FormatTyp.GrayBoldTitle),
|
||||
formatText(potwierdzenie.OpisPotwierdzenia?.LiczbaStron?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(potwierdzenie.OpisPotwierdzenia?.ZakresDokumentowOd)) {
|
||||
table.push([
|
||||
formatText('Zakres dokumentów od: ', FormatTyp.GrayBoldTitle),
|
||||
formatText(potwierdzenie.OpisPotwierdzenia?.ZakresDokumentowOd?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(potwierdzenie.OpisPotwierdzenia?.ZakresDokumentowDo)) {
|
||||
table.push([
|
||||
formatText('Zakres dokumentów do: ', FormatTyp.GrayBoldTitle),
|
||||
formatText(potwierdzenie.OpisPotwierdzenia?.ZakresDokumentowDo?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(potwierdzenie.OpisPotwierdzenia?.CalkowitaLiczbaDokumentow)) {
|
||||
table.push([
|
||||
formatText('Całkowita liczba dokumentów: ', FormatTyp.GrayBoldTitle),
|
||||
formatText(potwierdzenie.OpisPotwierdzenia?.CalkowitaLiczbaDokumentow?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
const idKontekstu: IDKontekstu | undefined = potwierdzenie?.Uwierzytelnienie?.IdKontekstu;
|
||||
|
||||
if (idKontekstu) {
|
||||
let typKontekstu = '';
|
||||
let id: string | number | undefined;
|
||||
|
||||
if (hasValue(idKontekstu.IdDostawcyUslugPeppol)) {
|
||||
typKontekstu = 'Identyfikator Peppol';
|
||||
id = getValue(idKontekstu.IdDostawcyUslugPeppol);
|
||||
}
|
||||
|
||||
if (hasValue(idKontekstu.Nip)) {
|
||||
typKontekstu = 'NIP';
|
||||
id = getValue(idKontekstu.Nip);
|
||||
}
|
||||
|
||||
if (hasValue(idKontekstu.IdWewnetrzny)) {
|
||||
typKontekstu = 'Identyfikator wewnętrzny';
|
||||
id = getValue(idKontekstu.IdWewnetrzny);
|
||||
}
|
||||
|
||||
if (hasValue(idKontekstu.IdZlozonyVatUE)) {
|
||||
typKontekstu = 'Identyfikator złożony';
|
||||
id = getValue(idKontekstu.IdZlozonyVatUE);
|
||||
}
|
||||
table.push([
|
||||
formatText('Typ kontekstu: ', FormatTyp.GrayBoldTitle),
|
||||
formatText(typKontekstu, FormatTyp.Default),
|
||||
]);
|
||||
table.push([
|
||||
formatText('Identyfikator kontekstu uwierzytelnienia: ', FormatTyp.GrayBoldTitle),
|
||||
formatText(id, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(potwierdzenie.Uwierzytelnienie?.SkrotDokumentuUwierzytelniajacego)) {
|
||||
table.push([
|
||||
formatText('Skrót dokumentu uwierzytelniającego: ', FormatTyp.GrayBoldTitle),
|
||||
formatText(potwierdzenie.Uwierzytelnienie?.SkrotDokumentuUwierzytelniajacego?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(potwierdzenie.NazwaStrukturyLogicznej)) {
|
||||
table.push([
|
||||
formatText(
|
||||
'Nazwa pliku XSD struktury logicznej dotycząca przesłanego dokumentu:',
|
||||
FormatTyp.GrayBoldTitle
|
||||
),
|
||||
formatText(potwierdzenie.NazwaStrukturyLogicznej?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(potwierdzenie.KodFormularza)) {
|
||||
table.push([
|
||||
formatText('Kod formularza przedłożonego dokumentu elektronicznego:', FormatTyp.GrayBoldTitle),
|
||||
formatText(potwierdzenie.KodFormularza?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
result.push([
|
||||
{
|
||||
unbreakable: true,
|
||||
table: {
|
||||
body: table,
|
||||
widths: ['auto', '*'],
|
||||
},
|
||||
layout: DEFAULT_TABLE_LAYOUT,
|
||||
} as Content,
|
||||
]);
|
||||
result.push(verticalSpacing(8));
|
||||
const definedHeader: HeaderDefine[] = [
|
||||
{ name: 'lp', title: 'Lp.', format: FormatTyp.Default },
|
||||
{
|
||||
name: 'NumerKSeFDokumentu',
|
||||
title: 'Numer identyfikujący fakturę w KSeF',
|
||||
format: FormatTyp.Default,
|
||||
},
|
||||
{ name: 'NumerFaktury', title: 'Numer faktury', format: FormatTyp.Default },
|
||||
{ name: 'NipSprzedawcy', title: 'NIP Sprzedawcy', format: FormatTyp.Default },
|
||||
{
|
||||
name: 'DataWystawieniaFaktury',
|
||||
title: 'Data wystawienia faktury',
|
||||
format: FormatTyp.Date,
|
||||
},
|
||||
{
|
||||
name: 'DataPrzeslaniaDokumentu',
|
||||
title: 'Data przesłania do KSeF',
|
||||
format: FormatTyp.DateTime,
|
||||
},
|
||||
{
|
||||
name: 'DataNadaniaNumeruKSeF',
|
||||
title: 'Data nadania numeru KSeF',
|
||||
format: FormatTyp.DateTime,
|
||||
},
|
||||
{
|
||||
name: 'SkrotDokumentu',
|
||||
title: 'Wartość funkcji skrótu złożonego dokumentu',
|
||||
format: FormatTyp.Default,
|
||||
},
|
||||
{
|
||||
name: 'TrybWysylki',
|
||||
title: 'Tryb wysyłki',
|
||||
format: FormatTyp.Default,
|
||||
width: '*',
|
||||
},
|
||||
];
|
||||
const documentData: Dokument[] =
|
||||
dokumenty.map((doc: Dokument, index: number): Dokument => {
|
||||
return { ...doc, lp: index + 1 };
|
||||
}) ?? [];
|
||||
|
||||
const tabDocument: FormContentState = getContentTable<(typeof documentData)[0]>(
|
||||
definedHeader,
|
||||
documentData,
|
||||
'auto'
|
||||
);
|
||||
|
||||
if (tabDocument.content) {
|
||||
result.push(tabDocument.content);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
34
src/lib-public/generators/UPO4_3/Naglowek.ts
Normal file
34
src/lib-public/generators/UPO4_3/Naglowek.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { Potwierdzenie } from '../../types/upo-v4_3.types';
|
||||
import { createLabelText, generateTwoColumns } from '../../../shared/PDF-functions';
|
||||
import { Position } from '../../../shared/enums/common.enum';
|
||||
|
||||
export function generateNaglowekUPO(potwierdzenie: Potwierdzenie): Content[] {
|
||||
return [
|
||||
generateTwoColumns(
|
||||
{
|
||||
text: [
|
||||
{ text: 'Krajowy System ', fontSize: 18 },
|
||||
{ text: 'e', color: 'red', bold: true, fontSize: 18 },
|
||||
{ text: '-Faktur', bold: true, fontSize: 18 },
|
||||
],
|
||||
},
|
||||
[
|
||||
{
|
||||
text: createLabelText(
|
||||
'Nazwa pełna podmiotu, któremu doręczono dokument elektroniczny: ',
|
||||
potwierdzenie!.NazwaPodmiotuPrzyjmujacego
|
||||
),
|
||||
alignment: Position.RIGHT,
|
||||
},
|
||||
{
|
||||
text: createLabelText(
|
||||
'Informacja o dokumencie: ',
|
||||
'Dokument został zarejestrowany w systemie teleinformatycznym Ministerstwa Finansów'
|
||||
),
|
||||
alignment: Position.RIGHT,
|
||||
},
|
||||
]
|
||||
),
|
||||
];
|
||||
}
|
||||
@@ -46,7 +46,7 @@ export function generateStopka(
|
||||
createSection(
|
||||
[
|
||||
{
|
||||
stack: createLabelText('Wytworzona w:', naglowek?.SystemInfo),
|
||||
stack: createLabelText('Wytworzona w: ', naglowek?.SystemInfo),
|
||||
margin: [0, 8, 0, 0],
|
||||
},
|
||||
],
|
||||
@@ -147,9 +147,13 @@ function generateQRCodeData(additionalData?: AdditionalDataTypes): Content[] {
|
||||
'Nie możesz zeskanować kodu z obrazka? Kliknij w link weryfikacyjny i przejdź do weryfikacji faktury!',
|
||||
FormatTyp.Value
|
||||
),
|
||||
{ stack: [formatText(additionalData.qrCode, FormatTyp.Link)], marginTop: 5 },
|
||||
{
|
||||
stack: [formatText(additionalData.qrCode, FormatTyp.Link)],
|
||||
marginTop: 5,
|
||||
link: additionalData.qrCode,
|
||||
},
|
||||
],
|
||||
link: additionalData.qrCode,
|
||||
|
||||
margin: [10, (qrCode.fit ?? 120) / 2 - 30, 0, 0],
|
||||
width: 'auto',
|
||||
} as ContentStack,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { shouldAddMarza } from './Wiersze';
|
||||
import { addMarza } from './Wiersze';
|
||||
import { TRodzajFaktury } from '../../../shared/consts/const';
|
||||
|
||||
const getMockFaVat = (mockedObjects?: Record<string, any>) =>
|
||||
@@ -13,34 +13,40 @@ const getMockFaVat = (mockedObjects?: Record<string, any>) =>
|
||||
|
||||
describe('shouldAddMarza', () => {
|
||||
it('returns P_12 when VAT type and P_12/P_12_XII are empty', () => {
|
||||
const result = shouldAddMarza(TRodzajFaktury.VAT, true, getMockFaVat());
|
||||
const result = addMarza(TRodzajFaktury.VAT, true, getMockFaVat());
|
||||
|
||||
expect(result).toEqual({ P_12: { _text: 'marża' } });
|
||||
});
|
||||
|
||||
it('returns P_12Z when ZAL type and P_12Z/P_12Z_XII are empty', () => {
|
||||
const result = shouldAddMarza(TRodzajFaktury.ZAL, true, getMockFaVat());
|
||||
const result = addMarza(TRodzajFaktury.ZAL, true, getMockFaVat());
|
||||
|
||||
expect(result).toEqual({ P_12Z: { _text: 'marża' } });
|
||||
});
|
||||
|
||||
it('returns null when rodzajFaktury is not a string', () => {
|
||||
const result = shouldAddMarza(undefined, true, getMockFaVat());
|
||||
expect(result).toBeNull();
|
||||
it('returns empty object when rodzajFaktury is not a string', () => {
|
||||
const result = addMarza(undefined, true, getMockFaVat());
|
||||
|
||||
expect(result).toMatchObject({});
|
||||
});
|
||||
|
||||
it('returns null when isP_PMarzy is false', () => {
|
||||
it('returns empty object when isP_PMarzy is false', () => {
|
||||
const mockP_12 = { P_12: { _text: '23' } };
|
||||
const result = shouldAddMarza(TRodzajFaktury.VAT, false, getMockFaVat(mockP_12));
|
||||
expect(result).toBeNull();
|
||||
const result = addMarza(TRodzajFaktury.VAT, false, getMockFaVat(mockP_12));
|
||||
|
||||
expect(result).toMatchObject({});
|
||||
});
|
||||
|
||||
it('returns null when P_12 already has value', () => {
|
||||
const mockP_12 = { P_12: { _text: '23' } };
|
||||
const result = shouldAddMarza(TRodzajFaktury.VAT, true, getMockFaVat(mockP_12));
|
||||
expect(result).toBeNull();
|
||||
const result = addMarza(TRodzajFaktury.VAT, true, getMockFaVat(mockP_12));
|
||||
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('returns null when rodzajFaktury is not VAT or ZAL type', () => {
|
||||
const result = shouldAddMarza(TRodzajFaktury.UPR, true, getMockFaVat());
|
||||
expect(result).toBeNull();
|
||||
const result = addMarza(TRodzajFaktury.UPR, true, getMockFaVat());
|
||||
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { TRodzajFaktury } from '../../../shared/consts/const';
|
||||
import { FP } from '../../types/fa1.types';
|
||||
import { getValue } from '../../../shared/PDF-functions';
|
||||
|
||||
export function shouldAddMarza(
|
||||
export function addMarza(
|
||||
rodzajFaktury: string | number | undefined,
|
||||
isP_PMarzy: boolean,
|
||||
wiersz: Record<string, FP>
|
||||
@@ -23,10 +23,10 @@ export function shouldAddMarza(
|
||||
} else if (isZALType && !getValue(wiersz.P_12Z) && !getValue(wiersz.P_12Z_XII)) {
|
||||
return { P_12Z: { _text: 'marża' } };
|
||||
} else {
|
||||
return null;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -128,13 +128,13 @@ function generateTable(tabela: Tabela): Content[] {
|
||||
return result;
|
||||
}
|
||||
|
||||
function createTable(cols: Kol[], rows: Wiersz[], subTableIndex: number, totalLength: number): ContentTable {
|
||||
function createTable(cols: Kol[], rows: Wiersz | Wiersz[], subTableIndex: number, totalLength: number): ContentTable {
|
||||
const definedHeader: Content[] = cols.map((item: Kol): string | ContentText =>
|
||||
formatText(item.NKom?._text, FormatTyp.GrayBoldTitle)
|
||||
);
|
||||
const tableBody: TableCell[] = [];
|
||||
|
||||
rows.forEach((item: Wiersz): void => {
|
||||
getTable(rows).forEach((item: Wiersz): void => {
|
||||
const WKom: FP[] = getTable(item.WKom);
|
||||
|
||||
while (WKom.length < totalLength) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { generateInvoice } from './generate-invoice';
|
||||
import { generatePDFUPO } from './UPO-4_2-generators';
|
||||
import { generatePDFUPO } from './UPO-generator';
|
||||
|
||||
export { generateInvoice, generatePDFUPO };
|
||||
|
||||
@@ -343,7 +343,7 @@ export interface Tabela {
|
||||
TMetaDane?: TMetaDane[];
|
||||
Opis?: FP;
|
||||
TNaglowek?: TNaglowek;
|
||||
Wiersz?: Wiersz[];
|
||||
Wiersz?: Wiersz | Wiersz[];
|
||||
Suma?: Suma;
|
||||
}
|
||||
|
||||
|
||||
69
src/lib-public/types/upo-v4_3.types.ts
Normal file
69
src/lib-public/types/upo-v4_3.types.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
export interface Upo {
|
||||
_declaration?: Declaration;
|
||||
_comment?: string;
|
||||
Potwierdzenie?: Potwierdzenie;
|
||||
}
|
||||
|
||||
export interface Potwierdzenie {
|
||||
_attributes?: PotwierdzenieAttributes;
|
||||
NazwaPodmiotuPrzyjmujacego?: KodFormularza;
|
||||
NumerReferencyjnySesji?: KodFormularza;
|
||||
Uwierzytelnienie?: Uwierzytelnienie;
|
||||
OpisPotwierdzenia?: OpisPotwierdzenia;
|
||||
NazwaStrukturyLogicznej?: KodFormularza;
|
||||
KodFormularza?: KodFormularza;
|
||||
Dokument?: Dokument[];
|
||||
}
|
||||
|
||||
export interface Dokument {
|
||||
lp?: number;
|
||||
NipSprzedawcy?: KodFormularza;
|
||||
NumerKSeFDokumentu?: KodFormularza;
|
||||
NumerFaktury?: KodFormularza;
|
||||
DataWystawieniaFaktury?: KodFormularza;
|
||||
DataPrzeslaniaDokumentu?: KodFormularza;
|
||||
DataNadaniaNumeruKSeF?: KodFormularza;
|
||||
SkrotDokumentu?: KodFormularza;
|
||||
TrybWysylki?: KodFormularza;
|
||||
}
|
||||
|
||||
export interface KodFormularza {
|
||||
_text?: string;
|
||||
}
|
||||
|
||||
export interface OpisPotwierdzenia {
|
||||
Strona?: KodFormularza;
|
||||
LiczbaStron?: KodFormularza;
|
||||
ZakresDokumentowOd?: KodFormularza;
|
||||
ZakresDokumentowDo?: KodFormularza;
|
||||
CalkowitaLiczbaDokumentow?: KodFormularza;
|
||||
}
|
||||
|
||||
export interface Uwierzytelnienie {
|
||||
IdKontekstu?: IDKontekstu;
|
||||
NumerReferencyjnyTokenaKSeF?: KodFormularza;
|
||||
SkrotDokumentuUwierzytelniajacego?: KodFormularza;
|
||||
}
|
||||
|
||||
export interface IDKontekstu {
|
||||
Nip?: KodFormularza;
|
||||
IdWewnetrzny?: KodFormularza;
|
||||
IdZlozonyVatUE?: KodFormularza;
|
||||
IdDostawcyUslugPeppol?: KodFormularza;
|
||||
}
|
||||
|
||||
export interface PotwierdzenieAttributes {
|
||||
upo?: string;
|
||||
xsi?: string;
|
||||
wersjaSchemy?: string;
|
||||
schemaLocation?: string;
|
||||
}
|
||||
|
||||
export interface Declaration {
|
||||
_attributes?: DeclarationAttributes;
|
||||
}
|
||||
|
||||
export interface DeclarationAttributes {
|
||||
version?: string;
|
||||
encoding?: string;
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
getNumberRounded,
|
||||
getValue,
|
||||
hasValue,
|
||||
normalizeCurrencySeparator,
|
||||
replaceDotWithCommaIfNeeded,
|
||||
verticalSpacing,
|
||||
} from './PDF-functions';
|
||||
import FormatTyp, { Position } from './enums/common.enum';
|
||||
@@ -126,3 +128,37 @@ describe('generateLine', () => {
|
||||
expect(lineContent).toHaveProperty('layout');
|
||||
});
|
||||
});
|
||||
|
||||
describe('normalized currency separator', () => {
|
||||
it('should correctly add zeros ', () => {
|
||||
const normalized = normalizeCurrencySeparator(43);
|
||||
|
||||
expect(normalized).toBe('43,00');
|
||||
});
|
||||
|
||||
it('should correctyl add zero', () => {
|
||||
const normalized = normalizeCurrencySeparator(43.7);
|
||||
|
||||
expect(normalized).toBe('43,70');
|
||||
});
|
||||
|
||||
it('should correctly displa value', () => {
|
||||
const normalized = normalizeCurrencySeparator('444,9999');
|
||||
|
||||
expect(normalized).toBe('444,9999');
|
||||
});
|
||||
});
|
||||
|
||||
describe('replaceDotWithCommaIfNeeded', () => {
|
||||
it('shuold change comma to dot if needed', () => {
|
||||
const dotToComma = replaceDotWithCommaIfNeeded(44.5);
|
||||
|
||||
expect(dotToComma).toBe('44,5');
|
||||
});
|
||||
|
||||
it('do nothing if do not find comma', () => {
|
||||
const dotToComma = replaceDotWithCommaIfNeeded(3);
|
||||
|
||||
expect(dotToComma).toBe('3');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,8 +10,14 @@ import {
|
||||
TableCell,
|
||||
TDocumentDefinitions,
|
||||
} from 'pdfmake/interfaces';
|
||||
import { DEFAULT_TABLE_LAYOUT, Kraj } from './consts/const';
|
||||
import { formatDateTime, getFormaPlatnosciString } from './generators/common/functions';
|
||||
import {
|
||||
DEFAULT_TABLE_LAYOUT,
|
||||
Kraj,
|
||||
TStawkaPodatku_FA1,
|
||||
TStawkaPodatku_FA2,
|
||||
TStawkaPodatku_FA3,
|
||||
} from './consts/const';
|
||||
import {formatDateTime, formatTime, getFormaPlatnosciString} from './generators/common/functions';
|
||||
import { HeaderDefine, PdfFP, PdfOptionField } from './types/pdf-types';
|
||||
import { FP } from '../lib-public/types/fa3.types';
|
||||
import { DifferentValues, FilteredKeysOfValues, TypesOfValues } from './types/universal.types';
|
||||
@@ -77,7 +83,7 @@ function formatValue(
|
||||
case FormatTyp.Currency:
|
||||
result.text = isNaN(Number(value))
|
||||
? (value as string)
|
||||
: `${dotToComma(Number(value).toFixed(2))} ${currency}`;
|
||||
: `${normalizeCurrencySeparator(value)} ${currency}`;
|
||||
result.alignment = Position.RIGHT;
|
||||
break;
|
||||
case FormatTyp.CurrencyAbs:
|
||||
@@ -104,6 +110,9 @@ function formatValue(
|
||||
case FormatTyp.Date:
|
||||
result.text = formatDateTime(value as string, false, true);
|
||||
break;
|
||||
case FormatTyp.Time:
|
||||
result.text = formatTime(value as string);
|
||||
break;
|
||||
case FormatTyp.FormOfPayment:
|
||||
result.text = getFormaPlatnosciString({ _text: value as string });
|
||||
break;
|
||||
@@ -113,9 +122,43 @@ function formatValue(
|
||||
case FormatTyp.Percentage:
|
||||
result.text = `${value}%`;
|
||||
break;
|
||||
case FormatTyp.Number:
|
||||
result.text = replaceDotWithCommaIfNeeded(value);
|
||||
result.alignment = Position.RIGHT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeCurrencySeparator(value: string | number | undefined): string {
|
||||
if (!value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const numberWithComma = dotToComma(typeof value === 'string' ? value : value.toString());
|
||||
|
||||
if (numberWithComma.includes(',')) {
|
||||
const parts = numberWithComma.split(',');
|
||||
|
||||
return parts[1].length > 1 ? numberWithComma : numberWithComma + '0';
|
||||
} else {
|
||||
return numberWithComma + ',00';
|
||||
}
|
||||
}
|
||||
|
||||
export function replaceDotWithCommaIfNeeded(value: string | number | undefined): string {
|
||||
let copyValue = '';
|
||||
|
||||
if (typeof value === 'number') {
|
||||
copyValue = value.toString();
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
copyValue = value;
|
||||
}
|
||||
|
||||
return copyValue.includes('.') ? dotToComma(copyValue) : copyValue;
|
||||
}
|
||||
|
||||
function dotToComma(value: string): string {
|
||||
return value.replace('.', ',');
|
||||
}
|
||||
@@ -466,11 +509,32 @@ export function verticalSpacing(height: number): ContentText {
|
||||
return { text: '\n', fontSize: height };
|
||||
}
|
||||
|
||||
export function getKraj(kod: string): string {
|
||||
if (Kraj[kod]) {
|
||||
return Kraj[kod];
|
||||
export function getKraj(code: string): string {
|
||||
if (Kraj[code]) {
|
||||
return Kraj[code];
|
||||
}
|
||||
return kod;
|
||||
return code;
|
||||
}
|
||||
|
||||
export function getTStawkaPodatku(code: string, version: 1 | 2 | 3): string {
|
||||
let TStawkaPodatkuVersioned: Record<string, string> = {};
|
||||
|
||||
switch (version) {
|
||||
case 1:
|
||||
TStawkaPodatkuVersioned = TStawkaPodatku_FA1;
|
||||
break;
|
||||
case 2:
|
||||
TStawkaPodatkuVersioned = TStawkaPodatku_FA2;
|
||||
break;
|
||||
case 3:
|
||||
TStawkaPodatkuVersioned = TStawkaPodatku_FA3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (TStawkaPodatkuVersioned[code]) {
|
||||
return TStawkaPodatkuVersioned[code];
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
export function generateLine(): Content {
|
||||
|
||||
@@ -16,6 +16,59 @@ export const TypKorekty: Record<string, string> = {
|
||||
'2': 'Korekta skutkująca w dacie wystawienia faktury korygującej',
|
||||
'3': 'Korekta skutkująca w dacie innej, w tym gdy dla różnych pozycji faktury korygującej daty te są różne',
|
||||
};
|
||||
export const TStawkaPodatku_FA1: Record<string, string> = {
|
||||
'23': '23%',
|
||||
'22': '22%',
|
||||
'8': '8%',
|
||||
'7': '7%',
|
||||
'5': '5%',
|
||||
'4': '4% lub 3% lub oo',
|
||||
'3': '4% lub 3% lub oo',
|
||||
'0': '0%',
|
||||
|
||||
zw: 'zwolnione z opodatkowania',
|
||||
oo: '4% lub 3% lub oo\n' +
|
||||
'UWAGA: oo jest wykazywane łącznie z 4% lub 3%',
|
||||
np: 'niepodlegające opodatkowaniu-transakcje dostawy towarów oraz świadczenia usług poza terytorium kraju',
|
||||
};
|
||||
|
||||
export const TStawkaPodatku_FA2: Record<string, string> = {
|
||||
'23': '23%',
|
||||
'22': '22%',
|
||||
'8': '8%',
|
||||
'7': '7%',
|
||||
'5': '5%',
|
||||
'4': '4%',
|
||||
'3': '3%',
|
||||
'0': '0%',
|
||||
|
||||
zw: 'zwolnione od podatku',
|
||||
oo: 'odwrotne obciążenie',
|
||||
np: 'niepodlegające opodatkowaniu-transakcje dostawy towarów oraz świadczenia usług poza terytorium kraju',
|
||||
};
|
||||
|
||||
export const TStawkaPodatku_FA3: Record<string, string> = {
|
||||
'23': '23%',
|
||||
'22': '22%',
|
||||
'8': '8%',
|
||||
'7': '7%',
|
||||
'5': '5%',
|
||||
'4': '4%',
|
||||
'3': '3%',
|
||||
|
||||
'0 KR':
|
||||
'0% - KR',
|
||||
'0 WDT': '0% - WDT',
|
||||
'0 EX': '0% - EX',
|
||||
|
||||
zw: 'zw',
|
||||
oo: 'oo',
|
||||
|
||||
'np I':
|
||||
'np I',
|
||||
'np II':
|
||||
'np II',
|
||||
};
|
||||
|
||||
export const Kraj: Record<string, string> = {
|
||||
AF: 'Afganistan',
|
||||
@@ -362,11 +415,11 @@ export const Procedura: Record<string, string> = {
|
||||
};
|
||||
|
||||
export const TableDataType: Record<string, FormatTyp> = {
|
||||
date: FormatTyp.DateTime,
|
||||
date: FormatTyp.Date,
|
||||
datetime: FormatTyp.DateTime,
|
||||
dec: FormatTyp.Currency,
|
||||
int: FormatTyp.Currency,
|
||||
time: FormatTyp.DateTime,
|
||||
time: FormatTyp.Time,
|
||||
txt: FormatTyp.Value,
|
||||
};
|
||||
|
||||
|
||||
@@ -38,8 +38,10 @@ export enum FormatTyp {
|
||||
Right = 'Right',
|
||||
DateTime = 'DateTime',
|
||||
Date = 'Date',
|
||||
Time = 'Time',
|
||||
FormOfPayment = 'FormOfPayment',
|
||||
Percentage = 'Percentage',
|
||||
Number = 'Number',
|
||||
}
|
||||
|
||||
export default FormatTyp;
|
||||
|
||||
@@ -29,21 +29,21 @@ describe('getRolaString', () => {
|
||||
|
||||
it('returns correct string for FA=1', () => {
|
||||
const key = Object.keys(FA1RolaPodmiotu3)[0];
|
||||
const expected = FA1RolaPodmiotu3[key as keyof typeof FA1RolaPodmiotu3].split('-')[0];
|
||||
const expected = FA1RolaPodmiotu3[key as keyof typeof FA1RolaPodmiotu3];
|
||||
|
||||
expect(getRolaString({ _text: key } as any, 1)).toBe(expected);
|
||||
});
|
||||
|
||||
it('returns correct string for FA=2', () => {
|
||||
const key = Object.keys(FA2RolaPodmiotu3)[0];
|
||||
const expected = FA2RolaPodmiotu3[key as keyof typeof FA2RolaPodmiotu3].split('-')[0];
|
||||
const expected = FA2RolaPodmiotu3[key as keyof typeof FA2RolaPodmiotu3];
|
||||
|
||||
expect(getRolaString({ _text: key } as any, 2)).toBe(expected);
|
||||
});
|
||||
|
||||
it('returns correct string for FA=3', () => {
|
||||
const key = Object.keys(FA3RolaPodmiotu3)[0];
|
||||
const expected = FA3RolaPodmiotu3[key as keyof typeof FA3RolaPodmiotu3].split('-')[0];
|
||||
const expected = FA3RolaPodmiotu3[key as keyof typeof FA3RolaPodmiotu3];
|
||||
|
||||
expect(getRolaString({ _text: key } as any, 3)).toBe(expected);
|
||||
});
|
||||
@@ -131,13 +131,13 @@ describe('formatDateTime', () => {
|
||||
it('formats date with seconds by default', () => {
|
||||
const date = '2025-10-03T12:15:30Z';
|
||||
|
||||
expect(formatDateTime(date)).toBe('2025-10-03 14:15:30');
|
||||
expect(formatDateTime(date)).toBe('03.10.2025 14:15:30');
|
||||
});
|
||||
|
||||
it('formats date without seconds if withoutSeconds true', () => {
|
||||
const date = '2025-10-03T12:15:30Z';
|
||||
|
||||
expect(formatDateTime(date, true)).toBe('2025-10-03 14:15');
|
||||
expect(formatDateTime(date, true)).toBe('03.10.2025 14:15');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -150,6 +150,6 @@ describe('getDateTimeWithoutSeconds', () => {
|
||||
it('returns formatted date without seconds if _text present', () => {
|
||||
const isoDate = { _text: '2025-10-03T12:15:30Z' } as any;
|
||||
|
||||
expect(getDateTimeWithoutSeconds(isoDate)).toBe('2025-10-03 14:15');
|
||||
expect(getDateTimeWithoutSeconds(isoDate)).toBe('03.10.2025 14:15');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,11 +18,11 @@ export function getRolaString(rola: FP2 | undefined, FA: 1 | 2 | 3): string {
|
||||
}
|
||||
switch (FA) {
|
||||
case 1:
|
||||
return FA1RolaPodmiotu3[rola._text as keyof typeof FA1RolaPodmiotu3].split('-')[0] ?? '';
|
||||
return FA1RolaPodmiotu3[rola._text as keyof typeof FA1RolaPodmiotu3];
|
||||
case 2:
|
||||
return FA2RolaPodmiotu3[rola._text as keyof typeof FA2RolaPodmiotu3].split('-')[0] ?? '';
|
||||
return FA2RolaPodmiotu3[rola._text as keyof typeof FA2RolaPodmiotu3];
|
||||
case 3:
|
||||
return FA3RolaPodmiotu3[rola._text as keyof typeof FA3RolaPodmiotu3].split('-')[0] ?? '';
|
||||
return FA3RolaPodmiotu3[rola._text as keyof typeof FA3RolaPodmiotu3];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +86,11 @@ export function formatDateTime(data?: string, withoutSeconds?: boolean, withoutT
|
||||
const seconds: string = dateTime.getSeconds().toString().padStart(2, '0');
|
||||
|
||||
if (withoutTime) {
|
||||
return `${year}-${month}-${day}`;
|
||||
return `${day}.${month}.${year}`;
|
||||
} else if (withoutSeconds) {
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
return `${day}.${month}.${year} ${hours}:${minutes}`;
|
||||
}
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
return `${day}.${month}.${year} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
export function getDateTimeWithoutSeconds(isoDate?: FP2): string {
|
||||
@@ -99,3 +99,22 @@ export function getDateTimeWithoutSeconds(isoDate?: FP2): string {
|
||||
}
|
||||
return formatDateTime(isoDate._text, true);
|
||||
}
|
||||
export function formatTime(data?: string, withoutSeconds?: boolean): string {
|
||||
if (!data) {
|
||||
return '';
|
||||
}
|
||||
const dateTime: Date = new Date(data);
|
||||
|
||||
if (isNaN(dateTime.getTime())) {
|
||||
return data;
|
||||
}
|
||||
|
||||
const hours: string = dateTime.getHours().toString().padStart(2, '0');
|
||||
const minutes: string = dateTime.getMinutes().toString().padStart(2, '0');
|
||||
const seconds: string = dateTime.getSeconds().toString().padStart(2, '0');
|
||||
|
||||
if (withoutSeconds) {
|
||||
return `${hours}:${minutes}`;
|
||||
}
|
||||
return `${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
Reference in New Issue
Block a user