add source code
This commit is contained in:
16
.gitignore
vendored
16
.gitignore
vendored
@@ -1,3 +1,17 @@
|
||||
node_modules/
|
||||
dist/
|
||||
*.log
|
||||
*.lock
|
||||
.DS_Store
|
||||
|
||||
.vite/
|
||||
coverage
|
||||
.vitest
|
||||
.cache
|
||||
temp
|
||||
out
|
||||
*.tsbuildinfo
|
||||
|
||||
.idea
|
||||
dist/
|
||||
.vscode
|
||||
*.swp
|
||||
9
.prettierignore
Normal file
9
.prettierignore
Normal file
@@ -0,0 +1,9 @@
|
||||
# Ignore artifacts:
|
||||
build
|
||||
/dist
|
||||
/coverage
|
||||
.angular
|
||||
/api
|
||||
README.md
|
||||
/src/app/core/services/api-deprecated.service.ts
|
||||
/src/app/core/services/api.service.ts
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": true,
|
||||
"attributeSort": "ASC",
|
||||
"singleAttributePerLine": true,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
|
||||
8
package-lock.json
generated
8
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "ksef-pdf-generator",
|
||||
"version": "0.0.26",
|
||||
"name": "@akmf/ksef-fe-invoice-converter",
|
||||
"version": "0.0.30",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ksef-pdf-generator",
|
||||
"version": "0.0.26",
|
||||
"name": "@akmf/ksef-fe-invoice-converter",
|
||||
"version": "0.0.30",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"pdfmake": "^0.2.20",
|
||||
|
||||
22
package.json
22
package.json
@@ -1,8 +1,24 @@
|
||||
{
|
||||
"name": "ksef-pdf-generator",
|
||||
"version": "0.0.26",
|
||||
"name": "@akmf/ksef-fe-invoice-converter",
|
||||
"version": "0.0.30",
|
||||
"scripts": {
|
||||
"start": "vite ./src/app"
|
||||
"dev": "vite --mode public --config vite.config.ts",
|
||||
"build": "vite build --mode production",
|
||||
"type": "tsc -p src/app-public/tsconfig.json --noEmit",
|
||||
"test": "vitest",
|
||||
"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",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/lib/index.d.ts",
|
||||
"import": "./ksef-fe-invoice-converter.es.js",
|
||||
"require": "./ksef-fe-invoice-converter.umd.js"
|
||||
}
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
||||
81
readme.md
81
readme.md
@@ -4,14 +4,15 @@ Biblioteka do generowania wizualizacji PDF faktur oraz UPO na podstawie plików
|
||||
|
||||
---
|
||||
|
||||
### Informacje wstępne
|
||||
## 1. Główne ustalenia
|
||||
|
||||
Niniejsza wersja Biblioteki stanowi wydanie wstępne, zawierające zbudowaną paczkę JavaScript oraz aplikacje służące do
|
||||
testowania rozwiązania.
|
||||
Wersja pełna, obejmująca kompletny kod źródłowy w TypeScript, możliwość budowania biblioteki oraz generowania typów TS,
|
||||
zostanie udostępniona w dniu 14 listopada 2025 r.
|
||||
Biblioteka zawiera następujące funkcjonalności:
|
||||
- Generowanie wizualizacji PDF faktur
|
||||
- Generowanie wizualizacji PDF UPO
|
||||
|
||||
## 1. Jak uruchomić aplikację
|
||||
---
|
||||
|
||||
## 2. Jak uruchomić aplikację pokazową
|
||||
|
||||
1. Zainstaluj Node.js w wersji **22.14.0**
|
||||
Możesz pobrać Node.js z oficjalnej strony: [https://nodejs.org](https://nodejs.org)
|
||||
@@ -29,14 +30,19 @@ zostanie udostępniona w dniu 14 listopada 2025 r.
|
||||
|
||||
4. Uruchom aplikację:
|
||||
```bash
|
||||
npm run start
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Aplikacja uruchomi się domyślnie pod adresem: [http://localhost:5173/](http://localhost:5173/)
|
||||
|
||||
---
|
||||
## 2.1 Budowanie bibliotki
|
||||
|
||||
## 2. Jak wygenerować fakturę
|
||||
1. Jak zbudować bibliotekę produkcyjnie:
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
## 3. Jak wygenerować fakturę
|
||||
|
||||
1. Po uruchomieniu aplikacji przejdź do **Wygeneruj wizualizacje faktury PDF**.
|
||||
2. Wybierz plik XML zgodny ze schemą **FA(1), FA(2) lub FA(3)**.
|
||||
@@ -48,7 +54,7 @@ Aplikacja uruchomi się domyślnie pod adresem: [http://localhost:5173/](http://
|
||||
|
||||
---
|
||||
|
||||
## 3. Jak wygenerować UPO
|
||||
## 4. Jak wygenerować UPO
|
||||
|
||||
1. Po uruchomieniu aplikacji przejdź do **Wygeneruj wizualizacje UPO PDF**.
|
||||
2. Wybierz plik XML zgodny ze schemą **UPO v4_2**.
|
||||
@@ -60,6 +66,61 @@ Aplikacja uruchomi się domyślnie pod adresem: [http://localhost:5173/](http://
|
||||
|
||||
---
|
||||
|
||||
## 5. Testy jednostkowe
|
||||
|
||||
Aplikacja zawiera zestaw testów napisanych w **TypeScript**, które weryfikują poprawność działania aplikacji.
|
||||
Projekt wykorzystuje **Vite** do bundlowania i **Vitest** jako framework testowy.
|
||||
|
||||
### Uruchamianie testów
|
||||
|
||||
1. Uruchom wszystkie testy:
|
||||
```bash
|
||||
npm run test
|
||||
```
|
||||
|
||||
2. Uruchom testy z interfejsem graficznym:
|
||||
```bash
|
||||
npm run test:ui
|
||||
```
|
||||
|
||||
3. Uruchom testy w trybie CI z raportem pokrycia:
|
||||
```bash
|
||||
npm run test:ci
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Raport: /coverage/index.html
|
||||
|
||||
---
|
||||
|
||||
### 1. Nazewnictwo zmiennych i metod
|
||||
|
||||
- **Polsko-angielskie nazwy** stosowane w zmiennych, typach i metodach wynikają bezpośrednio ze struktury pliku schemy
|
||||
faktury.
|
||||
Takie podejście zapewnia spójność i ujednolicenie nazewnictwa z definicją danych zawartą w schemie XML.
|
||||
|
||||
### 2. Struktura danych
|
||||
|
||||
- Struktura danych interfejsu FA odzwierciedla strukturę danych źródłowych pliku XML, zachowując ich logiczne powiązania
|
||||
i hierarchię
|
||||
w bardziej czytelnej formie.
|
||||
|
||||
### 3. Typy i interfejsy
|
||||
|
||||
- Typy odzwierciedlają strukturę danych pobieranych z XML faktur oraz ułatwiają generowanie PDF
|
||||
- Typy i interfejsy są definiowane w folderze types oraz plikach z rozszerzeniem types.ts.
|
||||
|
||||
---
|
||||
|
||||
## Dokumentacja używanych narzędzi
|
||||
|
||||
- Vitest Docs — https://vitest.dev/guide/
|
||||
- Vite Docs — https://vitejs.dev/guide/
|
||||
- TypeScript Handbook — https://www.typescriptlang.org/docs/
|
||||
|
||||
---
|
||||
|
||||
## Uwagi
|
||||
|
||||
- Upewnij się, że pliki XML są poprawnie sformatowane zgodnie z odpowiednią schemą.
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
|
||||
<script src="./main.ts" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
55
src/app-public/main.ts
Normal file
55
src/app-public/main.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { generateInvoice, generatePDFUPO } from '../lib-public';
|
||||
|
||||
import { AdditionalDataTypes } from '../lib-public/types/common.types';
|
||||
|
||||
const inputInvoice: HTMLInputElement = document.getElementById('xmlInput') as HTMLInputElement;
|
||||
const inputUPO: HTMLInputElement = document.getElementById('xmlInputUPO') as HTMLInputElement;
|
||||
|
||||
inputInvoice.addEventListener('change', async (): Promise<void> => {
|
||||
const file: File | undefined = inputInvoice.files?.[0];
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
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',
|
||||
};
|
||||
|
||||
generateInvoice(file, additionalData, 'blob').then((data: Blob): void => {
|
||||
const url: string = URL.createObjectURL(data);
|
||||
|
||||
const a: HTMLAnchorElement = document.createElement('a');
|
||||
|
||||
a.href = url;
|
||||
a.download = 'test.pdf';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
});
|
||||
|
||||
inputUPO.addEventListener('change', async (): Promise<void> => {
|
||||
const file: File | undefined = inputUPO.files?.[0];
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
generatePDFUPO(file).then((blob) => {
|
||||
const url: string = URL.createObjectURL(blob);
|
||||
|
||||
const a: HTMLAnchorElement = document.createElement('a');
|
||||
|
||||
a.href = url;
|
||||
a.download = 'test.pdf';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
});
|
||||
6
src/app-public/tsconfig.json
Normal file
6
src/app-public/tsconfig.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/types/public"
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,54 +0,0 @@
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
import { generateInvoice, generatePDFUPO } from './build/ksef-pdf-generator.es.js';
|
||||
|
||||
const input = document.getElementById('xmlInput') as HTMLInputElement;
|
||||
const inputUPO = document.getElementById('xmlInputUPO') as HTMLInputElement;
|
||||
|
||||
input.addEventListener('change', async () => {
|
||||
const file = input.files?.[0];
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
const additionalData: any = {
|
||||
nrKSeF: '5265877635-20250808-9231003CA67B-BE',
|
||||
qrCode:
|
||||
'https://ksef-te.mf.gov.pl/client-app/invoice/5265877635/26-10-2025/HS5E1zrA8WVjDNq_xMVIN5SD6nyRymmQ-BcYHReUAa0',
|
||||
}; // Example data
|
||||
|
||||
generateInvoice(file, additionalData, 'blob').then((data: any) => {
|
||||
const url = URL.createObjectURL(data);
|
||||
|
||||
const a = document.createElement('a');
|
||||
|
||||
a.href = url;
|
||||
a.download = 'test.pdf'; // nazwa pobieranego pliku
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
});
|
||||
|
||||
inputUPO.addEventListener('change', async () => {
|
||||
const file = inputUPO.files?.[0];
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
generatePDFUPO(file).then((blob: any) => {
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const a = document.createElement('a');
|
||||
|
||||
a.href = url;
|
||||
a.download = 'test.pdf'; // nazwa pobieranego pliku
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
});
|
||||
1
src/index.ts
Normal file
1
src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { generateInvoice, generatePDFUPO } from './lib-public';
|
||||
94
src/lib-public/FA1-generator.spec.ts
Normal file
94
src/lib-public/FA1-generator.spec.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import pdfMake from 'pdfmake/build/pdfmake';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generateFA1 } from './FA1-generator';
|
||||
import { Faktura } from './types/fa1.types';
|
||||
|
||||
import { AdditionalDataTypes } from './types/common.types';
|
||||
|
||||
vi.mock('./generators/FA1/Adnotacje', () => ({ generateAdnotacje: vi.fn(() => ({ example: 'adnotacje' })) }));
|
||||
vi.mock('./generators/FA1/DodatkoweInformacje', () => ({
|
||||
generateDodatkoweInformacje: vi.fn(() => ({ example: 'dodatkowe' })),
|
||||
}));
|
||||
vi.mock('./generators/FA1/Platnosc', () => ({ generatePlatnosc: vi.fn(() => ({ example: 'platnosc' })) }));
|
||||
vi.mock('./generators/FA1/Podmioty', () => ({ generatePodmioty: vi.fn(() => [{ example: 'podmioty' }]) }));
|
||||
vi.mock('./generators/FA1/PodsumowanieStawekPodatkuVat', () => ({
|
||||
generatePodsumowanieStawekPodatkuVat: vi.fn(() => ({ example: 'podsumowanie' })),
|
||||
}));
|
||||
vi.mock('./generators/FA1/Rabat', () => ({ generateRabat: vi.fn(() => ({ example: 'rabat' })) }));
|
||||
vi.mock('./generators/FA1/Szczegoly', () => ({ generateSzczegoly: vi.fn(() => ({ example: 'szczegoly' })) }));
|
||||
vi.mock('./generators/FA1/WarunkiTransakcji', () => ({
|
||||
generateWarunkiTransakcji: vi.fn(() => ({ example: 'warunki' })),
|
||||
}));
|
||||
vi.mock('./generators/FA1/Wiersze', () => ({ generateWiersze: vi.fn(() => ({ example: 'wiersze' })) }));
|
||||
vi.mock('./generators/FA1/Zamowienie', () => ({
|
||||
generateZamowienie: vi.fn(() => ({ example: 'zamowienie' })),
|
||||
}));
|
||||
vi.mock('./generators/common/DaneFaKorygowanej', () => ({
|
||||
generateDaneFaKorygowanej: vi.fn(() => ({ example: 'daneKorygowanej' })),
|
||||
}));
|
||||
vi.mock('./generators/common/Naglowek', () => ({ generateNaglowek: vi.fn(() => [{ example: 'naglowek' }]) }));
|
||||
vi.mock('./generators/common/Rozliczenie', () => ({
|
||||
generateRozliczenie: vi.fn(() => ({ example: 'rozliczenie' })),
|
||||
}));
|
||||
vi.mock('./generators/common/Stopka', () => ({ generateStopka: vi.fn(() => [{ example: 'stopka' }]) }));
|
||||
vi.mock('./PDF-functions', () => ({
|
||||
generateStyle: vi.fn(() => ({ styles: {}, defaultStyle: {} })),
|
||||
hasValue: vi.fn(() => true),
|
||||
}));
|
||||
|
||||
describe('generateFA1', () => {
|
||||
const mockCreatePdfReturn = { example: 'pdfCreatedObject' };
|
||||
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('calls pdfMake.createPdf and returns result (KOR with OkresFaKorygowanej, calls generateRabat)', () => {
|
||||
const invoice: Faktura = {
|
||||
Fa: {
|
||||
RodzajFaktury: { _text: 'KOR' },
|
||||
OkresFaKorygowanej: { _text: 'someValue' },
|
||||
Zamowienie: {},
|
||||
P_15: { _text: '15' },
|
||||
KodWaluty: { _text: 'PLN' },
|
||||
Adnotacje: {},
|
||||
Rozliczenie: {},
|
||||
Platnosc: {},
|
||||
WarunkiTransakcji: {},
|
||||
},
|
||||
Stopka: {},
|
||||
Naglowek: {},
|
||||
} as any;
|
||||
|
||||
const additionalData: AdditionalDataTypes = { nrKSeF: 'nrKSeF' };
|
||||
|
||||
const createPdfSpy = vi.spyOn(pdfMake, 'createPdf').mockReturnValue(mockCreatePdfReturn as any);
|
||||
|
||||
const result = generateFA1(invoice, additionalData);
|
||||
|
||||
expect(createPdfSpy).toHaveBeenCalled();
|
||||
expect(result).toBe(mockCreatePdfReturn);
|
||||
});
|
||||
|
||||
it('calls pdfMake.createPdf and returns result (non-KOR, calls generateWiersze)', () => {
|
||||
const invoice: Faktura = {
|
||||
Fa: {
|
||||
RodzajFaktury: { _text: 'VAT' },
|
||||
Zamowienie: {},
|
||||
P_15: { _text: '15' },
|
||||
KodWaluty: { _text: 'PLN' },
|
||||
},
|
||||
Stopka: {},
|
||||
Naglowek: {},
|
||||
} as any;
|
||||
|
||||
const additionalData: AdditionalDataTypes = { nrKSeF: 'nrKSeF' };
|
||||
|
||||
const createPdfSpy = vi.spyOn(pdfMake, 'createPdf').mockReturnValue(mockCreatePdfReturn as any);
|
||||
|
||||
const result = generateFA1(invoice, additionalData);
|
||||
|
||||
expect(createPdfSpy).toHaveBeenCalled();
|
||||
expect(result).toBe(mockCreatePdfReturn);
|
||||
});
|
||||
});
|
||||
56
src/lib-public/FA1-generator.ts
Normal file
56
src/lib-public/FA1-generator.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import pdfMake, { TCreatedPdf } from 'pdfmake/build/pdfmake';
|
||||
import pdfFonts from 'pdfmake/build/vfs_fonts';
|
||||
import { Content, TDocumentDefinitions } from 'pdfmake/interfaces';
|
||||
import { generateStyle, hasValue } from '../shared/PDF-functions';
|
||||
import { TRodzajFaktury } from '../shared/consts/const';
|
||||
import { generateAdnotacje } from './generators/FA1/Adnotacje';
|
||||
import { generateDodatkoweInformacje } from './generators/FA1/DodatkoweInformacje';
|
||||
import { generatePlatnosc } from './generators/FA1/Platnosc';
|
||||
import { generatePodmioty } from './generators/FA1/Podmioty';
|
||||
import { generatePodsumowanieStawekPodatkuVat } from './generators/FA1/PodsumowanieStawekPodatkuVat';
|
||||
import { generateRabat } from './generators/FA1/Rabat';
|
||||
import { generateSzczegoly } from './generators/FA1/Szczegoly';
|
||||
import { generateWarunkiTransakcji } from './generators/FA1/WarunkiTransakcji';
|
||||
import { generateWiersze } from './generators/FA1/Wiersze';
|
||||
import { generateZamowienie } from './generators/FA1/Zamowienie';
|
||||
import { generateDaneFaKorygowanej } from './generators/common/DaneFaKorygowanej';
|
||||
import { generateNaglowek } from './generators/common/Naglowek';
|
||||
import { generateRozliczenie } from './generators/common/Rozliczenie';
|
||||
import { generateStopka } from './generators/common/Stopka';
|
||||
import { Faktura } from './types/fa1.types';
|
||||
import { ZamowienieKorekta } from './enums/invoice.enums';
|
||||
import { AdditionalDataTypes } from './types/common.types';
|
||||
|
||||
pdfMake.vfs = pdfFonts.vfs;
|
||||
|
||||
export function generateFA1(invoice: Faktura, additionalData: AdditionalDataTypes): TCreatedPdf {
|
||||
const isKOR_RABAT: boolean =
|
||||
invoice.Fa?.RodzajFaktury?._text == TRodzajFaktury.KOR && hasValue(invoice.Fa?.OkresFaKorygowanej);
|
||||
const rabatOrRowsInvoice: Content = isKOR_RABAT ? generateRabat(invoice.Fa!) : generateWiersze(invoice.Fa!);
|
||||
const docDefinition: TDocumentDefinitions = {
|
||||
content: [
|
||||
...generateNaglowek(invoice.Fa, additionalData),
|
||||
generateDaneFaKorygowanej(invoice.Fa),
|
||||
...generatePodmioty(invoice),
|
||||
generateSzczegoly(invoice.Fa!),
|
||||
rabatOrRowsInvoice,
|
||||
generateZamowienie(
|
||||
invoice.Fa?.Zamowienie,
|
||||
ZamowienieKorekta.Order,
|
||||
invoice.Fa?.P_15?._text ?? '',
|
||||
invoice.Fa?.RodzajFaktury?._text ?? '',
|
||||
invoice.Fa?.KodWaluty?._text ?? ''
|
||||
),
|
||||
generatePodsumowanieStawekPodatkuVat(invoice),
|
||||
generateAdnotacje(invoice.Fa?.Adnotacje),
|
||||
generateDodatkoweInformacje(invoice.Fa!),
|
||||
generateRozliczenie(invoice.Fa?.Rozliczenie, invoice.Fa?.KodWaluty?._text ?? ''),
|
||||
generatePlatnosc(invoice.Fa?.Platnosc),
|
||||
generateWarunkiTransakcji(invoice.Fa?.WarunkiTransakcji),
|
||||
...generateStopka(additionalData, invoice.Stopka, invoice.Naglowek, invoice.Fa?.WZ),
|
||||
],
|
||||
...generateStyle(),
|
||||
};
|
||||
|
||||
return pdfMake.createPdf(docDefinition);
|
||||
}
|
||||
93
src/lib-public/FA2-generator.spec.ts
Normal file
93
src/lib-public/FA2-generator.spec.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import pdfMake from 'pdfmake/build/pdfmake';
|
||||
import { Faktura } from './types/fa2.types';
|
||||
import { generateFA2 } from './FA2-generator';
|
||||
import { AdditionalDataTypes } from './types/common.types';
|
||||
|
||||
vi.mock('./generators/FA2/Adnotacje', () => ({ generateAdnotacje: vi.fn(() => ({ example: 'adnotacje' })) }));
|
||||
vi.mock('./generators/FA2/DodatkoweInformacje', () => ({
|
||||
generateDodatkoweInformacje: vi.fn(() => ({ example: 'dodatkowe' })),
|
||||
}));
|
||||
vi.mock('./generators/FA2/Platnosc', () => ({ generatePlatnosc: vi.fn(() => ({ example: 'platnosc' })) }));
|
||||
vi.mock('./generators/FA2/Podmioty', () => ({ generatePodmioty: vi.fn(() => [{ example: 'podmioty' }]) }));
|
||||
vi.mock('./generators/FA2/PodsumowanieStawekPodatkuVat', () => ({
|
||||
generatePodsumowanieStawekPodatkuVat: vi.fn(() => ({ example: 'podsumowanie' })),
|
||||
}));
|
||||
vi.mock('./generators/FA2/Rabat', () => ({ generateRabat: vi.fn(() => ({ example: 'rabat' })) }));
|
||||
vi.mock('./generators/FA2/Szczegoly', () => ({ generateSzczegoly: vi.fn(() => ({ example: 'szczegoly' })) }));
|
||||
vi.mock('./generators/FA2/WarunkiTransakcji', () => ({
|
||||
generateWarunkiTransakcji: vi.fn(() => ({ example: 'warunki' })),
|
||||
}));
|
||||
vi.mock('./generators/FA2/Wiersze', () => ({ generateWiersze: vi.fn(() => ({ example: 'wiersze' })) }));
|
||||
vi.mock('./generators/FA2/Zamowienie', () => ({
|
||||
generateZamowienie: vi.fn(() => ({ example: 'zamowienie' })),
|
||||
}));
|
||||
vi.mock('./generators/common/DaneFaKorygowanej', () => ({
|
||||
generateDaneFaKorygowanej: vi.fn(() => ({ example: 'daneKorygowanej' })),
|
||||
}));
|
||||
vi.mock('./generators/common/Naglowek', () => ({ generateNaglowek: vi.fn(() => [{ example: 'naglowek' }]) }));
|
||||
vi.mock('./generators/common/Rozliczenie', () => ({
|
||||
generateRozliczenie: vi.fn(() => ({ example: 'rozliczenie' })),
|
||||
}));
|
||||
vi.mock('./generators/common/Stopka', () => ({ generateStopka: vi.fn(() => [{ example: 'stopka' }]) }));
|
||||
vi.mock('./PDF-functions', () => ({
|
||||
generateStyle: vi.fn(() => ({ styles: {}, defaultStyle: {} })),
|
||||
hasValue: vi.fn(() => true),
|
||||
}));
|
||||
|
||||
describe('generateFA2', () => {
|
||||
const mockCreatePdfReturn = { example: 'pdfCreatedObject' };
|
||||
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('calls pdfMake.createPdf and returns result (KOR with OkresFaKorygowanej, uses generateRabat)', () => {
|
||||
const invoice: Faktura = {
|
||||
Fa: {
|
||||
RodzajFaktury: { _text: 'KOR' },
|
||||
OkresFaKorygowanej: { _text: 'someValue' },
|
||||
Zamowienie: {},
|
||||
P_15: { _text: '15' },
|
||||
KodWaluty: { _text: 'PLN' },
|
||||
Adnotacje: {},
|
||||
Rozliczenie: {},
|
||||
Platnosc: {},
|
||||
WarunkiTransakcji: {},
|
||||
},
|
||||
Stopka: {},
|
||||
Naglowek: {},
|
||||
} as any;
|
||||
|
||||
const additionalData: AdditionalDataTypes = { nrKSeF: 'nrKSeF' };
|
||||
|
||||
const createPdfSpy = vi.spyOn(pdfMake, 'createPdf').mockReturnValue(mockCreatePdfReturn as any);
|
||||
|
||||
const result = generateFA2(invoice, additionalData);
|
||||
|
||||
expect(createPdfSpy).toHaveBeenCalled();
|
||||
expect(result).toBe(mockCreatePdfReturn);
|
||||
});
|
||||
|
||||
it('calls pdfMake.createPdf and returns result (non-KOR, uses generateWiersze)', () => {
|
||||
const invoice: Faktura = {
|
||||
Fa: {
|
||||
RodzajFaktury: { _text: 'VAT' },
|
||||
Zamowienie: {},
|
||||
P_15: { _text: '15' },
|
||||
KodWaluty: { _text: 'PLN' },
|
||||
},
|
||||
Stopka: {},
|
||||
Naglowek: {},
|
||||
} as any;
|
||||
|
||||
const additionalData: AdditionalDataTypes = { nrKSeF: 'nrKSeF' };
|
||||
|
||||
const createPdfSpy = vi.spyOn(pdfMake, 'createPdf').mockReturnValue(mockCreatePdfReturn as any);
|
||||
|
||||
const result = generateFA2(invoice, additionalData);
|
||||
|
||||
expect(createPdfSpy).toHaveBeenCalled();
|
||||
expect(result).toBe(mockCreatePdfReturn);
|
||||
});
|
||||
});
|
||||
56
src/lib-public/FA2-generator.ts
Normal file
56
src/lib-public/FA2-generator.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import pdfMake, { TCreatedPdf } from 'pdfmake/build/pdfmake';
|
||||
import pdfFonts from 'pdfmake/build/vfs_fonts';
|
||||
import { Content, TDocumentDefinitions } from 'pdfmake/interfaces';
|
||||
import { generateStyle, hasValue } from '../shared/PDF-functions';
|
||||
import { TRodzajFaktury } from '../shared/consts/const';
|
||||
import { generateAdnotacje } from './generators/FA2/Adnotacje';
|
||||
import { generateDodatkoweInformacje } from './generators/FA2/DodatkoweInformacje';
|
||||
import { generatePlatnosc } from './generators/FA2/Platnosc';
|
||||
import { generatePodmioty } from './generators/FA2/Podmioty';
|
||||
import { generatePodsumowanieStawekPodatkuVat } from './generators/FA2/PodsumowanieStawekPodatkuVat';
|
||||
import { generateRabat } from './generators/FA2/Rabat';
|
||||
import { generateSzczegoly } from './generators/FA2/Szczegoly';
|
||||
import { generateWarunkiTransakcji } from './generators/FA2/WarunkiTransakcji';
|
||||
import { generateWiersze } from './generators/FA2/Wiersze';
|
||||
import { generateZamowienie } from './generators/FA2/Zamowienie';
|
||||
import { generateDaneFaKorygowanej } from './generators/common/DaneFaKorygowanej';
|
||||
import { generateNaglowek } from './generators/common/Naglowek';
|
||||
import { generateRozliczenie } from './generators/common/Rozliczenie';
|
||||
import { generateStopka } from './generators/common/Stopka';
|
||||
import { Faktura } from './types/fa2.types';
|
||||
import { ZamowienieKorekta } from './enums/invoice.enums';
|
||||
import { AdditionalDataTypes } from './types/common.types';
|
||||
|
||||
pdfMake.vfs = pdfFonts.vfs;
|
||||
|
||||
export function generateFA2(invoice: Faktura, additionalData: AdditionalDataTypes): TCreatedPdf {
|
||||
const isKOR_RABAT: boolean =
|
||||
invoice.Fa?.RodzajFaktury?._text == TRodzajFaktury.KOR && hasValue(invoice.Fa?.OkresFaKorygowanej);
|
||||
const rabatOrRowsInvoice: Content = isKOR_RABAT ? generateRabat(invoice.Fa!) : generateWiersze(invoice.Fa!);
|
||||
const docDefinition: TDocumentDefinitions = {
|
||||
content: [
|
||||
...generateNaglowek(invoice.Fa, additionalData),
|
||||
generateDaneFaKorygowanej(invoice.Fa),
|
||||
...generatePodmioty(invoice),
|
||||
generateSzczegoly(invoice.Fa!),
|
||||
rabatOrRowsInvoice,
|
||||
generateZamowienie(
|
||||
invoice.Fa?.Zamowienie,
|
||||
ZamowienieKorekta.Order,
|
||||
invoice.Fa?.P_15?._text ?? '',
|
||||
invoice.Fa?.RodzajFaktury?._text ?? '',
|
||||
invoice.Fa?.KodWaluty?._text ?? ''
|
||||
),
|
||||
generatePodsumowanieStawekPodatkuVat(invoice),
|
||||
generateAdnotacje(invoice.Fa?.Adnotacje),
|
||||
generateDodatkoweInformacje(invoice.Fa!),
|
||||
generateRozliczenie(invoice.Fa?.Rozliczenie, invoice.Fa?.KodWaluty?._text ?? ''),
|
||||
generatePlatnosc(invoice.Fa?.Platnosc),
|
||||
generateWarunkiTransakcji(invoice.Fa?.WarunkiTransakcji),
|
||||
...generateStopka(additionalData, invoice.Stopka, invoice.Naglowek, invoice.Fa?.WZ),
|
||||
],
|
||||
...generateStyle(),
|
||||
};
|
||||
|
||||
return pdfMake.createPdf(docDefinition);
|
||||
}
|
||||
100
src/lib-public/FA3-generator.spec.ts
Normal file
100
src/lib-public/FA3-generator.spec.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import pdfMake, { TCreatedPdf } from 'pdfmake/build/pdfmake';
|
||||
import { beforeEach, describe, expect, it, MockInstance, vi } from 'vitest';
|
||||
import { generateFA3 } from './FA3-generator';
|
||||
import { Faktura } from './types/fa3.types';
|
||||
|
||||
import { AdditionalDataTypes } from './types/common.types';
|
||||
|
||||
vi.mock('./generators/FA3/Adnotacje', () => ({ generateAdnotacje: vi.fn(() => ({ example: 'adnotacje' })) }));
|
||||
vi.mock('./generators/FA3/DodatkoweInformacje', () => ({
|
||||
generateDodatkoweInformacje: vi.fn(() => ({ example: 'dodatkowe' })),
|
||||
}));
|
||||
vi.mock('./generators/FA3/Platnosc', () => ({ generatePlatnosc: vi.fn(() => ({ example: 'platnosc' })) }));
|
||||
vi.mock('./generators/FA3/Podmioty', () => ({ generatePodmioty: vi.fn(() => [{ example: 'podmioty' }]) }));
|
||||
vi.mock('./generators/FA3/PodsumowanieStawekPodatkuVat', () => ({
|
||||
generatePodsumowanieStawekPodatkuVat: vi.fn(() => ({ example: 'podsumowanie' })),
|
||||
}));
|
||||
vi.mock('./generators/FA3/Rabat', () => ({ generateRabat: vi.fn(() => ({ example: 'rabat' })) }));
|
||||
vi.mock('./generators/FA3/Szczegoly', () => ({ generateSzczegoly: vi.fn(() => ({ example: 'szczegoly' })) }));
|
||||
vi.mock('./generators/FA3/WarunkiTransakcji', () => ({
|
||||
generateWarunkiTransakcji: vi.fn(() => ({ example: 'warunki' })),
|
||||
}));
|
||||
vi.mock('./generators/FA3/Wiersze', () => ({ generateWiersze: vi.fn(() => ({ example: 'wiersze' })) }));
|
||||
vi.mock('./generators/FA3/Zamowienie', () => ({
|
||||
generateZamowienie: vi.fn(() => ({ example: 'zamowienie' })),
|
||||
}));
|
||||
vi.mock('./generators/common/DaneFaKorygowanej', () => ({
|
||||
generateDaneFaKorygowanej: vi.fn(() => ({ example: 'daneKorygowanej' })),
|
||||
}));
|
||||
vi.mock('./generators/common/Naglowek', () => ({ generateNaglowek: vi.fn(() => [{ example: 'naglowek' }]) }));
|
||||
vi.mock('./generators/common/Rozliczenie', () => ({
|
||||
generateRozliczenie: vi.fn(() => ({ example: 'rozliczenie' })),
|
||||
}));
|
||||
vi.mock('./generators/common/Stopka', () => ({ generateStopka: vi.fn(() => [{ example: 'stopka' }]) }));
|
||||
vi.mock('./PDF-functions', () => ({
|
||||
generateStyle: vi.fn(() => ({ styles: {}, defaultStyle: {} })),
|
||||
hasValue: vi.fn(() => true),
|
||||
}));
|
||||
|
||||
describe('generateFA3', (): void => {
|
||||
const mockCreatePdfReturn = { example: 'pdfCreatedObject' };
|
||||
|
||||
beforeEach((): void => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('should call pdfMake.createPdf and return its result (KOR with OkresFaKorygowanej, call generateRabat)', () => {
|
||||
const invoice: Faktura = {
|
||||
Fa: {
|
||||
RodzajFaktury: { _text: 'KOR' },
|
||||
OkresFaKorygowanej: { _text: 'someValue' },
|
||||
Zamowienie: {},
|
||||
P_15: { _text: '15' },
|
||||
KodWaluty: { _text: 'PLN' },
|
||||
Adnotacje: {},
|
||||
Rozliczenie: {},
|
||||
Platnosc: {},
|
||||
WarunkiTransakcji: {},
|
||||
},
|
||||
Zalacznik: {},
|
||||
Stopka: {},
|
||||
Naglowek: {},
|
||||
} as any;
|
||||
|
||||
const additionalData: AdditionalDataTypes = { nrKSeF: 'nrKSeF' };
|
||||
|
||||
const createPdfSpy: MockInstance = vi
|
||||
.spyOn(pdfMake, 'createPdf')
|
||||
.mockReturnValue(mockCreatePdfReturn as any);
|
||||
|
||||
const result: TCreatedPdf = generateFA3(invoice, additionalData);
|
||||
|
||||
expect(createPdfSpy).toHaveBeenCalled();
|
||||
expect(result).toBe(mockCreatePdfReturn);
|
||||
});
|
||||
|
||||
it('should call pdfMake.createPdf and return its result (non-KOR, call generateWiersze)', () => {
|
||||
const invoice: Faktura = {
|
||||
Fa: {
|
||||
RodzajFaktury: { _text: 'VAT' },
|
||||
Zamowienie: {},
|
||||
P_15: { _text: '15' },
|
||||
KodWaluty: { _text: 'PLN' },
|
||||
},
|
||||
Zalacznik: {},
|
||||
Stopka: {},
|
||||
Naglowek: {},
|
||||
} as any;
|
||||
|
||||
const additionalData: AdditionalDataTypes = { nrKSeF: 'nrKSeF' };
|
||||
|
||||
const createPdfSpy: MockInstance = vi
|
||||
.spyOn(pdfMake, 'createPdf')
|
||||
.mockReturnValue(mockCreatePdfReturn as any);
|
||||
|
||||
const result: TCreatedPdf = generateFA3(invoice, additionalData);
|
||||
|
||||
expect(createPdfSpy).toHaveBeenCalled();
|
||||
expect(result).toBe(mockCreatePdfReturn);
|
||||
});
|
||||
});
|
||||
56
src/lib-public/FA3-generator.ts
Normal file
56
src/lib-public/FA3-generator.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import pdfMake, { TCreatedPdf } from 'pdfmake/build/pdfmake';
|
||||
import pdfFonts from 'pdfmake/build/vfs_fonts';
|
||||
import { Content, TDocumentDefinitions } from 'pdfmake/interfaces';
|
||||
import { generateStyle, hasValue } from '../shared/PDF-functions';
|
||||
import { TRodzajFaktury } from '../shared/consts/const';
|
||||
import { generateAdnotacje } from './generators/FA3/Adnotacje';
|
||||
import { generateDodatkoweInformacje } from './generators/FA3/DodatkoweInformacje';
|
||||
import { generatePlatnosc } from './generators/FA3/Platnosc';
|
||||
import { generatePodmioty } from './generators/FA3/Podmioty';
|
||||
import { generatePodsumowanieStawekPodatkuVat } from './generators/FA3/PodsumowanieStawekPodatkuVat';
|
||||
import { generateRabat } from './generators/FA3/Rabat';
|
||||
import { generateSzczegoly } from './generators/FA3/Szczegoly';
|
||||
import { generateWarunkiTransakcji } from './generators/FA3/WarunkiTransakcji';
|
||||
import { generateWiersze } from './generators/FA3/Wiersze';
|
||||
import { generateZamowienie } from './generators/FA3/Zamowienie';
|
||||
import { generateDaneFaKorygowanej } from './generators/common/DaneFaKorygowanej';
|
||||
import { generateNaglowek } from './generators/common/Naglowek';
|
||||
import { generateRozliczenie } from './generators/common/Rozliczenie';
|
||||
import { generateStopka } from './generators/common/Stopka';
|
||||
import { Faktura } from './types/fa3.types';
|
||||
import { ZamowienieKorekta } from './enums/invoice.enums';
|
||||
import { AdditionalDataTypes } from './types/common.types';
|
||||
|
||||
pdfMake.vfs = pdfFonts.vfs;
|
||||
|
||||
export function generateFA3(invoice: Faktura, additionalData: AdditionalDataTypes): TCreatedPdf {
|
||||
const isKOR_RABAT: boolean =
|
||||
invoice.Fa?.RodzajFaktury?._text == TRodzajFaktury.KOR && hasValue(invoice.Fa?.OkresFaKorygowanej);
|
||||
const rabatOrRowsInvoice: Content = isKOR_RABAT ? generateRabat(invoice.Fa!) : generateWiersze(invoice.Fa!);
|
||||
const docDefinition: TDocumentDefinitions = {
|
||||
content: [
|
||||
...generateNaglowek(invoice.Fa, additionalData, invoice.Zalacznik),
|
||||
generateDaneFaKorygowanej(invoice.Fa),
|
||||
...generatePodmioty(invoice),
|
||||
generateSzczegoly(invoice.Fa!),
|
||||
rabatOrRowsInvoice,
|
||||
generateZamowienie(
|
||||
invoice.Fa?.Zamowienie,
|
||||
ZamowienieKorekta.Order,
|
||||
invoice.Fa?.P_15?._text ?? '',
|
||||
invoice.Fa?.RodzajFaktury?._text ?? '',
|
||||
invoice.Fa?.KodWaluty?._text ?? ''
|
||||
),
|
||||
generatePodsumowanieStawekPodatkuVat(invoice),
|
||||
generateAdnotacje(invoice.Fa?.Adnotacje),
|
||||
generateDodatkoweInformacje(invoice.Fa!),
|
||||
generateRozliczenie(invoice.Fa?.Rozliczenie, invoice.Fa?.KodWaluty?._text ?? ''),
|
||||
generatePlatnosc(invoice.Fa?.Platnosc),
|
||||
generateWarunkiTransakcji(invoice.Fa?.WarunkiTransakcji),
|
||||
...generateStopka(additionalData, invoice.Stopka, invoice.Naglowek, invoice.Fa?.WZ, invoice.Zalacznik),
|
||||
],
|
||||
...generateStyle(),
|
||||
};
|
||||
|
||||
return pdfMake.createPdf(docDefinition);
|
||||
}
|
||||
65
src/lib-public/UPO-4_2-generators.spec.ts
Normal file
65
src/lib-public/UPO-4_2-generators.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-4_2-generators';
|
||||
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-4_2-generators.ts
Normal file
35
src/lib-public/UPO-4_2-generators.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 { generateNaglowekUPO } from './generators/UPO4_2/Naglowek';
|
||||
import { generateDokumnetUPO } from './generators/UPO4_2/Dokumenty';
|
||||
import { parseXML } from '../shared/XML-parser';
|
||||
import { Position } from '../shared/enums/common.enum';
|
||||
|
||||
export async function generatePDFUPO(file: File): Promise<Blob> {
|
||||
const upo = (await parseXML(file)) as Upo;
|
||||
const docDefinition: TDocumentDefinitions = {
|
||||
content: [generateNaglowekUPO(upo.Potwierdzenie!), generateDokumnetUPO(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');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
5
src/lib-public/enums/invoice.enums.ts
Normal file
5
src/lib-public/enums/invoice.enums.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export enum ZamowienieKorekta {
|
||||
BeforeCorrection = 'Zamówienie przed korektą',
|
||||
AfterCorrection = 'Zamówienie po korekcie',
|
||||
Order = 'Zamówienie',
|
||||
}
|
||||
102
src/lib-public/generate-invoice.spec.ts
Normal file
102
src/lib-public/generate-invoice.spec.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import * as FA1Generator from './FA1-generator';
|
||||
import * as FA2Generator from './FA2-generator';
|
||||
import * as FA3Generator from './FA3-generator';
|
||||
import { generateInvoice } from './generate-invoice';
|
||||
import * as XMLParser from '../shared/XML-parser';
|
||||
import { AdditionalDataTypes } from './types/common.types';
|
||||
|
||||
describe('generateInvoice', () => {
|
||||
const mockBlob = new Blob(['mock pdf content'], { type: 'application/pdf' });
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
const additionalData: AdditionalDataTypes = {
|
||||
nrKSeF: 'testKSeF',
|
||||
qrCode: 'qrCodeValue',
|
||||
isMobile: false,
|
||||
};
|
||||
|
||||
it('should call generateFA1 and resolve with blob for version FA (1)', async () => {
|
||||
const fakeXml = {
|
||||
Faktura: {
|
||||
Naglowek: {
|
||||
KodFormularza: {
|
||||
_attributes: { kodSystemowy: 'FA (1)' },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
vi.spyOn(XMLParser, 'parseXML').mockResolvedValue(fakeXml);
|
||||
|
||||
const getBlobMock = vi.fn().mockImplementation((cb) => cb(mockBlob));
|
||||
|
||||
vi.spyOn(FA1Generator, 'generateFA1').mockReturnValue({ getBlob: getBlobMock } as any);
|
||||
|
||||
const file = new File([], 'test.xml');
|
||||
|
||||
const result = await generateInvoice(file, additionalData, 'blob');
|
||||
|
||||
expect(result).toBe(mockBlob);
|
||||
expect(XMLParser.parseXML).toHaveBeenCalledWith(file);
|
||||
expect(FA1Generator.generateFA1).toHaveBeenCalledWith(fakeXml.Faktura, additionalData);
|
||||
expect(getBlobMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call generateFA2 and resolve with blob for version FA (2)', async () => {
|
||||
const fakeXml = {
|
||||
Faktura: {
|
||||
Naglowek: {
|
||||
KodFormularza: {
|
||||
_attributes: { kodSystemowy: 'FA (2)' },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
vi.spyOn(XMLParser, 'parseXML').mockResolvedValue(fakeXml);
|
||||
|
||||
const getBlobMock = vi.fn().mockImplementation((cb) => cb(mockBlob));
|
||||
|
||||
vi.spyOn(FA2Generator, 'generateFA2').mockReturnValue({ getBlob: getBlobMock } as any);
|
||||
|
||||
const file = new File([], 'test.xml');
|
||||
|
||||
const result = await generateInvoice(file, additionalData, 'blob');
|
||||
|
||||
expect(result).toBe(mockBlob);
|
||||
expect(XMLParser.parseXML).toHaveBeenCalledWith(file);
|
||||
expect(FA2Generator.generateFA2).toHaveBeenCalledWith(fakeXml.Faktura, additionalData);
|
||||
expect(getBlobMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call generateFA3 and resolve with blob for version FA (3)', async () => {
|
||||
const fakeXml = {
|
||||
Faktura: {
|
||||
Naglowek: {
|
||||
KodFormularza: {
|
||||
_attributes: { kodSystemowy: 'FA (3)' },
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
vi.spyOn(XMLParser, 'parseXML').mockResolvedValue(fakeXml);
|
||||
|
||||
const getBlobMock = vi.fn().mockImplementation((cb) => cb(mockBlob));
|
||||
|
||||
vi.spyOn(FA3Generator, 'generateFA3').mockReturnValue({ getBlob: getBlobMock } as any);
|
||||
|
||||
const file = new File([], 'test.xml');
|
||||
|
||||
const result = await generateInvoice(file, additionalData, 'blob');
|
||||
|
||||
expect(result).toBe(mockBlob);
|
||||
expect(XMLParser.parseXML).toHaveBeenCalledWith(file);
|
||||
expect(FA3Generator.generateFA3).toHaveBeenCalledWith(fakeXml.Faktura, additionalData);
|
||||
expect(getBlobMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
59
src/lib-public/generate-invoice.ts
Normal file
59
src/lib-public/generate-invoice.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { generateFA1 } from './FA1-generator';
|
||||
import { Faktura as Faktura1 } from './types/fa1.types';
|
||||
import { generateFA2 } from './FA2-generator';
|
||||
import { Faktura as Faktura2 } from './types/fa2.types';
|
||||
import { generateFA3 } from './FA3-generator';
|
||||
import { Faktura as Faktura3 } from './types/fa3.types';
|
||||
import { parseXML } from '../shared/XML-parser';
|
||||
import { TCreatedPdf } from 'pdfmake/build/pdfmake';
|
||||
import { AdditionalDataTypes } from './types/common.types';
|
||||
|
||||
export async function generateInvoice(
|
||||
file: File,
|
||||
additionalData: AdditionalDataTypes,
|
||||
formatType: 'blob'
|
||||
): Promise<Blob>;
|
||||
export async function generateInvoice(
|
||||
file: File,
|
||||
additionalData: AdditionalDataTypes,
|
||||
formatType: 'base64'
|
||||
): Promise<string>;
|
||||
export async function generateInvoice(
|
||||
file: File,
|
||||
additionalData: AdditionalDataTypes,
|
||||
formatType: FormatType = 'blob'
|
||||
): Promise<FormatTypeResult> {
|
||||
const xml: unknown = await parseXML(file);
|
||||
const wersja: any = (xml as any)?.Faktura?.Naglowek?.KodFormularza?._attributes?.kodSystemowy;
|
||||
|
||||
let pdf: TCreatedPdf;
|
||||
|
||||
return new Promise((resolve): void => {
|
||||
switch (wersja) {
|
||||
case 'FA (1)':
|
||||
pdf = generateFA1((xml as any).Faktura as Faktura1, additionalData);
|
||||
break;
|
||||
case 'FA (2)':
|
||||
pdf = generateFA2((xml as any).Faktura as Faktura2, additionalData);
|
||||
break;
|
||||
case 'FA (3)':
|
||||
pdf = generateFA3((xml as any).Faktura as Faktura3, additionalData);
|
||||
break;
|
||||
}
|
||||
switch (formatType) {
|
||||
case 'blob':
|
||||
pdf.getBlob((blob: Blob): void => {
|
||||
resolve(blob);
|
||||
});
|
||||
break;
|
||||
case 'base64':
|
||||
default:
|
||||
pdf.getBase64((base64: string): void => {
|
||||
resolve(base64);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
type FormatType = 'blob' | 'base64';
|
||||
type FormatTypeResult = Blob | string;
|
||||
122
src/lib-public/generators/FA1/Adnotacje.spec.ts
Normal file
122
src/lib-public/generators/FA1/Adnotacje.spec.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generateAdnotacje } from './Adnotacje';
|
||||
import { Adnotacje } from '../../types/fa1.types';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn().mockImplementation((label) => ({ text: `HEADER:${label}` })),
|
||||
createLabelText: vi.fn().mockImplementation((label, value) => [{ text: `LABEL:${label}${value}` }]),
|
||||
formatText: vi.fn().mockImplementation((text) => ({ text })),
|
||||
hasValue: vi.fn((val) => Boolean(val && val._text)),
|
||||
verticalSpacing: vi.fn().mockImplementation((size) => ({ text: `SPACING:${size}` })),
|
||||
}));
|
||||
|
||||
describe(generateAdnotacje.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('returns an empty array when argument is undefined', () => {
|
||||
const result = generateAdnotacje(undefined);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('adds annotation P_19 and also P_19A, P_19B, P_19C', () => {
|
||||
const adnotacje: Adnotacje = {
|
||||
P_19: { _text: '1' },
|
||||
P_19A: { _text: 'tekst19A' },
|
||||
P_19B: { _text: 'tekst19B' },
|
||||
P_19C: { _text: 'tekst19C' },
|
||||
};
|
||||
const result = generateAdnotacje(adnotacje);
|
||||
|
||||
expect(result.some((el) => JSON.stringify(el).includes('HEADER:Adnotacje'))).toBeTruthy();
|
||||
expect(
|
||||
result.some((el) =>
|
||||
JSON.stringify(el).includes('LABEL:Przepis ustawy albo aktu wydanego na podstawie ustawy: tekst19A')
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
result.some((el) => JSON.stringify(el).includes('LABEL:Przepis dyrektywy: tekst19B'))
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
result.some((el) => JSON.stringify(el).includes('LABEL:Inna podstawa prawna: tekst19C'))
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('adds "Split payment mechanism" annotation when P_18A = 1', () => {
|
||||
const adnotacje: Adnotacje = { P_18A: { _text: '1' } };
|
||||
const result = generateAdnotacje(adnotacje);
|
||||
|
||||
expect(result.some((el) => JSON.stringify(el).includes('Mechanizm podzielonej płatności'))).toBeTruthy();
|
||||
});
|
||||
|
||||
it('adds correct texts for cash method/reverse charge/simplified procedure', () => {
|
||||
const adnotacje: Adnotacje = {
|
||||
P_16: { _text: '1' },
|
||||
P_18: { _text: '1' },
|
||||
P_23: { _text: '1' },
|
||||
};
|
||||
const result = generateAdnotacje(adnotacje);
|
||||
|
||||
expect(JSON.stringify(result)).toContain('Metoda kasowa');
|
||||
expect(JSON.stringify(result)).toContain('Odwrotne obciążenie');
|
||||
expect(JSON.stringify(result)).toContain('Procedura trójstronna uproszczona');
|
||||
});
|
||||
|
||||
it('adds "Self-billing" when P_17=1', () => {
|
||||
const adnotacje: Adnotacje = { P_17: { _text: '1' } };
|
||||
const result = generateAdnotacje(adnotacje);
|
||||
|
||||
expect(JSON.stringify(result)).toContain('Samofakturowanie');
|
||||
});
|
||||
|
||||
it('adds margin annotation based on subtypes', () => {
|
||||
const adnotacje: Adnotacje = {
|
||||
P_PMarzy: { _text: '1' },
|
||||
P_PMarzy_3_2: { _text: '1' }, // works of art
|
||||
};
|
||||
const result = generateAdnotacje(adnotacje);
|
||||
|
||||
expect(JSON.stringify(result)).toContain('dzieła sztuki');
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateAdnotacje - additional coverage', () => {
|
||||
it('adds correct margin annotation for all subtypes', () => {
|
||||
const variants = [
|
||||
{ key: 'P_PMarzy_3_1', expected: 'towary używane' },
|
||||
{ key: 'P_PMarzy_2', expected: 'biura podróży' },
|
||||
{ key: 'P_PMarzy_3_3', expected: 'przedmioty kolekcjonerskie i antyki' },
|
||||
];
|
||||
|
||||
variants.forEach(({ key, expected }) => {
|
||||
const adnotacje: any = {
|
||||
P_PMarzy: { _text: '1' },
|
||||
[key]: { _text: '1' },
|
||||
};
|
||||
const result = generateAdnotacje(adnotacje);
|
||||
expect(JSON.stringify(result)).toContain(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles P_22 and calls generateDostawy', () => {
|
||||
const adnotacje: any = { P_22: { _text: '1' } };
|
||||
const result = generateAdnotacje(adnotacje);
|
||||
expect(JSON.stringify(result)).toContain('Wewnątrzwspólnotowe dostawy nowych środków transportu');
|
||||
});
|
||||
|
||||
it('returns empty array if adnotacje has no valid fields', () => {
|
||||
const adnotacje: any = { P_99: { _text: '' } };
|
||||
const result = generateAdnotacje(adnotacje);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('adds header and spacing when result has items', () => {
|
||||
const adnotacje: any = { P_16: { _text: '1' } };
|
||||
const result = generateAdnotacje(adnotacje) as any;
|
||||
const resultString = JSON.stringify(result);
|
||||
expect(resultString).toContain('HEADER:Adnotacje');
|
||||
expect(resultString).toContain('SPACING:1');
|
||||
});
|
||||
});
|
||||
301
src/lib-public/generators/FA1/Adnotacje.ts
Normal file
301
src/lib-public/generators/FA1/Adnotacje.ts
Normal file
@@ -0,0 +1,301 @@
|
||||
import { Content, ContentTable } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
formatText,
|
||||
hasValue,
|
||||
verticalSpacing,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { Adnotacje } from '../../types/fa1.types';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { DEFAULT_TABLE_LAYOUT } from '../../../shared/consts/const';
|
||||
|
||||
export function generateAdnotacje(adnotacje?: Adnotacje): Content[] {
|
||||
const result: Content[] = [];
|
||||
let firstColumn: Content[] = [];
|
||||
const secondColumn: Content[] = [];
|
||||
|
||||
if (adnotacje) {
|
||||
if (adnotacje?.P_19?._text === '1') {
|
||||
addToColumn(
|
||||
firstColumn,
|
||||
secondColumn,
|
||||
{
|
||||
text: 'Dostawa towarów lub świadczenie usług zwolnionych od podatku na podstawie art. 43 ust. 1, art. 113 ust. 1 i 9 albo przepisów wydanych na podstawie art. 82 ust. 3 lub na podstawie innych przepisów',
|
||||
},
|
||||
true
|
||||
);
|
||||
if (adnotacje.P_19A?._text) {
|
||||
addToColumn(
|
||||
firstColumn,
|
||||
secondColumn,
|
||||
createLabelText(
|
||||
'Podstawa zwolnienia od podatku: ',
|
||||
'Przepis ustawy albo aktu wydanego na podstawie ustawy, na podstawie którego podatnik stosuje adnotacje od podatku'
|
||||
),
|
||||
true
|
||||
);
|
||||
addToColumn(
|
||||
firstColumn,
|
||||
secondColumn,
|
||||
createLabelText('Przepis ustawy albo aktu wydanego na podstawie ustawy: ', adnotacje.P_19A._text),
|
||||
true
|
||||
);
|
||||
}
|
||||
if (adnotacje.P_19B?._text) {
|
||||
addToColumn(
|
||||
firstColumn,
|
||||
secondColumn,
|
||||
createLabelText(
|
||||
'Podstawa zwolnienia od podatku: ',
|
||||
'Przepis dyrektywy 2006/112/WE, który zwalnia od podatku taką dostawę towarów lub takie świadczenie usług'
|
||||
),
|
||||
true
|
||||
);
|
||||
addToColumn(
|
||||
firstColumn,
|
||||
secondColumn,
|
||||
createLabelText('Przepis dyrektywy: ', adnotacje.P_19B._text),
|
||||
true
|
||||
);
|
||||
}
|
||||
if (adnotacje.P_19C?._text) {
|
||||
addToColumn(
|
||||
firstColumn,
|
||||
secondColumn,
|
||||
createLabelText(
|
||||
'Podstawa zwolnienia od podatku: ',
|
||||
'Inna podstawa prawna wskazującą na to, że dostawa towarów lub świadczenie usług korzysta ze zwolnienia'
|
||||
),
|
||||
true
|
||||
);
|
||||
addToColumn(
|
||||
firstColumn,
|
||||
secondColumn,
|
||||
createLabelText('Inna podstawa prawna: ', adnotacje.P_19C._text),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (adnotacje.P_18A?._text === '1') {
|
||||
addToColumn(firstColumn, secondColumn, { text: 'Mechanizm podzielonej płatności' });
|
||||
}
|
||||
if (adnotacje.P_16?._text === '1') {
|
||||
addToColumn(firstColumn, secondColumn, { text: 'Metoda kasowa' });
|
||||
}
|
||||
if (adnotacje.P_18?._text === '1') {
|
||||
addToColumn(firstColumn, secondColumn, { text: 'Odwrotne obciążenie' });
|
||||
}
|
||||
if (adnotacje.P_23?._text === '1') {
|
||||
addToColumn(firstColumn, secondColumn, { text: 'Procedura trójstronna uproszczona' });
|
||||
}
|
||||
|
||||
if (adnotacje.P_PMarzy?._text === '1') {
|
||||
let valueMarzy = '';
|
||||
|
||||
if (adnotacje.P_PMarzy_3_1?._text === '1') {
|
||||
valueMarzy = 'towary używane';
|
||||
} else if (adnotacje.P_PMarzy_3_2?._text === '1') {
|
||||
valueMarzy = 'dzieła sztuki';
|
||||
} else if (adnotacje.P_PMarzy_2?._text === '1') {
|
||||
valueMarzy = 'biura podróży';
|
||||
} else if (adnotacje.P_PMarzy_3_3?._text === '1') {
|
||||
valueMarzy = 'przedmioty kolekcjonerskie i antyki';
|
||||
}
|
||||
addToColumn(firstColumn, secondColumn, createLabelText('Procedura marży: ', valueMarzy));
|
||||
}
|
||||
|
||||
if (adnotacje.P_17?._text === '1') {
|
||||
addToColumn(firstColumn, secondColumn, { text: 'Samofakturowanie' });
|
||||
}
|
||||
|
||||
if (adnotacje.P_22?._text === '1') {
|
||||
let obowiazekVAT: Content[] = [];
|
||||
|
||||
obowiazekVAT = [...createLabelText('Wewnątrzwspólnotowe dostawy nowych środków transportu', ' ')];
|
||||
if (obowiazekVAT) {
|
||||
firstColumn = [firstColumn, ...obowiazekVAT];
|
||||
}
|
||||
}
|
||||
|
||||
if (firstColumn.length || secondColumn.length) {
|
||||
result.push({ columns: [firstColumn, secondColumn], columnGap: 20 });
|
||||
}
|
||||
|
||||
if (result.length) {
|
||||
result.unshift(verticalSpacing(1));
|
||||
result.unshift(createHeader('Adnotacje'));
|
||||
result.unshift(verticalSpacing(1));
|
||||
result.push(verticalSpacing(1));
|
||||
}
|
||||
|
||||
if (adnotacje.P_22?._text === '1') {
|
||||
result.push(generateDostawy(adnotacje));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function generateDostawy(adnotacje: Adnotacje): Content[] {
|
||||
const result: Content[] = [];
|
||||
const table: Content[][] = [];
|
||||
const anyP22B =
|
||||
hasValue(adnotacje.P_22B) ||
|
||||
hasValue(adnotacje.P_22BT) ||
|
||||
hasValue(adnotacje.P_22B1) ||
|
||||
hasValue(adnotacje.P_22B2) ||
|
||||
hasValue(adnotacje.P_22B3) ||
|
||||
hasValue(adnotacje.P_22B4);
|
||||
const anyP22C: boolean = hasValue(adnotacje.P_22C) || hasValue(adnotacje.P_22C1);
|
||||
const anyP22D: boolean = hasValue(adnotacje.P_22D) || hasValue(adnotacje.P_22D1);
|
||||
|
||||
if (hasValue(adnotacje.P_22A)) {
|
||||
table.push([
|
||||
formatText('Data dopuszczenia nowego środka transportu do użytku', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22A?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22BMK)) {
|
||||
table.push([
|
||||
formatText('Marka nowego środka transportu', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22BMK?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22BMD)) {
|
||||
table.push([
|
||||
formatText('Model nowego środka transportu', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22BMD?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22BK)) {
|
||||
table.push([
|
||||
formatText('Kolor nowego środka transportu', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22BK?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22BNR)) {
|
||||
table.push([
|
||||
formatText('Numer rejestracyjny nowego środka transportu', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22BNR?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22BRP)) {
|
||||
table.push([
|
||||
formatText('Rok produkcji nowego środka transportu', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22BRP?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (anyP22B) {
|
||||
table.push([
|
||||
formatText('Rodzaj pojazdu', FormatTyp.GrayBoldTitle),
|
||||
formatText(
|
||||
'Dostawa dotyczy pojazdów lądowych, o których mowa w art. 2 pkt 10 lit. a ustawy',
|
||||
FormatTyp.Default
|
||||
),
|
||||
]);
|
||||
if (hasValue(adnotacje.P_22B)) {
|
||||
table.push([
|
||||
formatText('Przebieg pojazdu', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22B?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22B1)) {
|
||||
table.push([
|
||||
formatText('Numer VIN', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22B1?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22B2)) {
|
||||
table.push([
|
||||
formatText('Numer nadwozia', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22B2?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22B3)) {
|
||||
table.push([
|
||||
formatText('Numer podwozia', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22B3?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22B4)) {
|
||||
table.push([
|
||||
formatText('Numer ramy', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22B4?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22BT)) {
|
||||
table.push([
|
||||
formatText('Typ nowego środka transportu', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22BT?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
} else if (anyP22C) {
|
||||
table.push([
|
||||
formatText('Rodzaj pojazdu', FormatTyp.GrayBoldTitle),
|
||||
formatText(
|
||||
'Dostawa dotyczy jednostek pływających, o których mowa w art. 2 pkt 10 lit. b ustawy',
|
||||
FormatTyp.Default
|
||||
),
|
||||
]);
|
||||
if (hasValue(adnotacje.P_22C)) {
|
||||
table.push([
|
||||
formatText('Przebieg pojazdu', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22C?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22C1)) {
|
||||
table.push([
|
||||
formatText('Numer kadłuba nowego środka transportu', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22C1?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
} else if (anyP22D) {
|
||||
table.push([
|
||||
formatText('Rodzaj pojazdu', FormatTyp.GrayBoldTitle),
|
||||
formatText(
|
||||
'Dostawa dotyczy statków powietrznych, o których mowa w art. 2 pkt 10 lit. c ustawy',
|
||||
FormatTyp.Default
|
||||
),
|
||||
]);
|
||||
if (hasValue(adnotacje.P_22D)) {
|
||||
table.push([
|
||||
formatText('Przebieg pojazdu', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22D?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (hasValue(adnotacje.P_22D1)) {
|
||||
table.push([
|
||||
formatText('Numer fabryczny nowego środka transportu<', FormatTyp.GrayBoldTitle),
|
||||
formatText(adnotacje.P_22D1?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (table.length) {
|
||||
result.push([
|
||||
{
|
||||
unbreakable: true,
|
||||
table: {
|
||||
body: table,
|
||||
widths: ['*', '*'],
|
||||
},
|
||||
layout: DEFAULT_TABLE_LAYOUT,
|
||||
} as ContentTable,
|
||||
]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function addToColumn(
|
||||
firstColumn: Content[],
|
||||
secondColumn: Content[],
|
||||
content: Content,
|
||||
isFirstColumn?: boolean
|
||||
): void {
|
||||
if (firstColumn.length > secondColumn.length && isFirstColumn) {
|
||||
secondColumn.push(content);
|
||||
return;
|
||||
}
|
||||
firstColumn.push(content);
|
||||
}
|
||||
43
src/lib-public/generators/FA1/Adnotacje2.spec.ts
Normal file
43
src/lib-public/generators/FA1/Adnotacje2.spec.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generateDostawy } from './Adnotacje';
|
||||
import { Adnotacje } from '../../types/fa1.types';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
formatText: vi.fn((text, format) => ({ text, format })),
|
||||
hasValue: vi.fn((val) => Boolean(val && val._text)),
|
||||
}));
|
||||
const formatText = vi.fn((text, format) => ({ text, format }));
|
||||
const hasValue = vi.fn((val) => Boolean(val && val._text));
|
||||
|
||||
describe(generateDostawy.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
hasValue.mockImplementation((val) => Boolean(val && val._text));
|
||||
});
|
||||
|
||||
it('returns empty array when no values', () => {
|
||||
const adnotacje: Adnotacje = {};
|
||||
const result = generateDostawy(adnotacje);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('creates table for P_22A–P_22BRP fields', () => {
|
||||
const adnotacje: Adnotacje = {
|
||||
P_22A: { _text: '2024-01-01' },
|
||||
P_22BMK: { _text: 'Ford' },
|
||||
P_22BMD: { _text: 'Focus' },
|
||||
P_22BK: { _text: 'Red' },
|
||||
P_22BNR: { _text: 'ABC123' },
|
||||
P_22BRP: { _text: '2023' },
|
||||
};
|
||||
const result = generateDostawy(adnotacje);
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('does not create table when no valid values found', () => {
|
||||
const adnotacje: Adnotacje = { P_22D: { _text: '' } };
|
||||
hasValue.mockReturnValue(false);
|
||||
const result = generateDostawy(adnotacje);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
105
src/lib-public/generators/FA1/Adres.spec.ts
Normal file
105
src/lib-public/generators/FA1/Adres.spec.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { Adres } from '../../types/fa1.types';
|
||||
import { generateAdres } from './Adres';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createLabelText: vi.fn().mockImplementation((label, value) => [{ text: `LABEL:${label}${value._text}` }]),
|
||||
}));
|
||||
|
||||
describe('generateAdres', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('returns an empty array when both AdresPol and AdresZagr are undefined', () => {
|
||||
const adres: Adres = {};
|
||||
const result = generateAdres(adres);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('creates correct fields for foreign address (AdresZagr)', () => {
|
||||
const adres: Adres = {
|
||||
AdresZagr: {
|
||||
KodKraju: { _text: 'PL' },
|
||||
Ulica: { _text: 'Example Street' },
|
||||
NrDomu: { _text: '123' },
|
||||
NrLokalu: { _text: '4A' },
|
||||
KodPocztowy: { _text: '00-123' },
|
||||
Miejscowosc: { _text: 'Warsaw' },
|
||||
GLN: { _text: '123456789' },
|
||||
},
|
||||
};
|
||||
const result = generateAdres(adres);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([
|
||||
[{ text: 'LABEL:Kraj: PL' }],
|
||||
[{ text: 'LABEL:Ulica: Example Street' }],
|
||||
[{ text: 'LABEL:Numer domu: 123' }],
|
||||
[{ text: 'LABEL:Numer lokalu: 4A' }],
|
||||
[{ text: 'LABEL:Kod pocztowy: 00-123' }],
|
||||
[{ text: 'LABEL:Miejscowość: Warsaw' }],
|
||||
[{ text: 'LABEL:GLN: 123456789' }],
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('creates correct fields for Polish address (AdresPol)', () => {
|
||||
const adres: Adres = {
|
||||
AdresPol: {
|
||||
Wojewodztwo: { _text: 'Mazowieckie' },
|
||||
Powiat: { _text: 'Warszawa' },
|
||||
Gmina: { _text: 'Centrum' },
|
||||
Ulica: { _text: 'Main' },
|
||||
NrDomu: { _text: '5' },
|
||||
NrLokalu: { _text: '12B' },
|
||||
KodPocztowy: { _text: '01-234' },
|
||||
Miejscowosc: { _text: 'Warsaw' },
|
||||
Poczta: { _text: 'Warsaw 1' },
|
||||
GLN: { _text: '987654321' },
|
||||
},
|
||||
};
|
||||
const result = generateAdres(adres);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([
|
||||
[{ text: 'LABEL:Województwo: Mazowieckie' }],
|
||||
[{ text: 'LABEL:Powiat: Warszawa' }],
|
||||
[{ text: 'LABEL:Gmina: Centrum' }],
|
||||
[{ text: 'LABEL:Ulica: Main' }],
|
||||
[{ text: 'LABEL:Numer domu: 5' }],
|
||||
[{ text: 'LABEL:Numer lokalu: 12B' }],
|
||||
[{ text: 'LABEL:Kod pocztowy: 01-234' }],
|
||||
[{ text: 'LABEL:Miejscowość: Warsaw' }],
|
||||
[{ text: 'LABEL:Poczta: Warsaw 1' }],
|
||||
[{ text: 'LABEL:GLN: 987654321' }],
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('works correctly when both AdresPol and AdresZagr exist', () => {
|
||||
const adres: Adres = {
|
||||
AdresPol: { Miejscowosc: { _text: 'Katowice' } },
|
||||
AdresZagr: { Miejscowosc: { _text: 'Berlin' } },
|
||||
};
|
||||
const result = generateAdres(adres);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([
|
||||
[{ text: 'LABEL:Miejscowość: Katowice' }],
|
||||
[{ text: 'LABEL:Miejscowość: Berlin' }],
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('skips undefined fields in AdresPol and AdresZagr', () => {
|
||||
const adres: Adres = {
|
||||
AdresPol: {},
|
||||
AdresZagr: {},
|
||||
};
|
||||
const result = generateAdres(adres);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
69
src/lib-public/generators/FA1/Adres.ts
Normal file
69
src/lib-public/generators/FA1/Adres.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { createLabelText } from '../../../shared/PDF-functions';
|
||||
import { Adres, FP } from '../../types/fa1.types';
|
||||
|
||||
export function generateAdres(adres: Adres): Content[] {
|
||||
const result: Content[] = [];
|
||||
|
||||
if (adres.AdresZagr) {
|
||||
const adresZagr: Record<string, FP> = adres.AdresZagr;
|
||||
|
||||
if (adresZagr.KodKraju) {
|
||||
result.push(createLabelText('Kraj: ', adresZagr.KodKraju));
|
||||
}
|
||||
if (adresZagr.Ulica) {
|
||||
result.push(createLabelText('Ulica: ', adresZagr.Ulica));
|
||||
}
|
||||
if (adresZagr.NrDomu) {
|
||||
result.push(createLabelText('Numer domu: ', adresZagr.NrDomu));
|
||||
}
|
||||
if (adresZagr.NrLokalu) {
|
||||
result.push(createLabelText('Numer lokalu: ', adresZagr.NrLokalu));
|
||||
}
|
||||
if (adresZagr.KodPocztowy) {
|
||||
result.push(createLabelText('Kod pocztowy: ', adresZagr.KodPocztowy));
|
||||
}
|
||||
if (adresZagr.Miejscowosc) {
|
||||
result.push(createLabelText('Miejscowość: ', adresZagr.Miejscowosc));
|
||||
}
|
||||
if (adresZagr.GLN) {
|
||||
result.push(createLabelText('GLN: ', adresZagr.GLN));
|
||||
}
|
||||
}
|
||||
|
||||
if (adres.AdresPol) {
|
||||
const adresPol: Record<string, FP> = adres.AdresPol;
|
||||
|
||||
if (adresPol.Wojewodztwo) {
|
||||
result.push(createLabelText('Województwo: ', adresPol.Wojewodztwo));
|
||||
}
|
||||
if (adresPol.Powiat) {
|
||||
result.push(createLabelText('Powiat: ', adresPol.Powiat));
|
||||
}
|
||||
if (adresPol.Gmina) {
|
||||
result.push(createLabelText('Gmina: ', adresPol.Gmina));
|
||||
}
|
||||
if (adresPol.Ulica) {
|
||||
result.push(createLabelText('Ulica: ', adresPol.Ulica));
|
||||
}
|
||||
if (adresPol.NrDomu) {
|
||||
result.push(createLabelText('Numer domu: ', adresPol.NrDomu));
|
||||
}
|
||||
if (adresPol.NrLokalu) {
|
||||
result.push(createLabelText('Numer lokalu: ', adresPol.NrLokalu));
|
||||
}
|
||||
if (adresPol.KodPocztowy) {
|
||||
result.push(createLabelText('Kod pocztowy: ', adresPol.KodPocztowy));
|
||||
}
|
||||
if (adresPol.Miejscowosc) {
|
||||
result.push(createLabelText('Miejscowość: ', adresPol.Miejscowosc));
|
||||
}
|
||||
if (adresPol.Poczta) {
|
||||
result.push(createLabelText('Poczta: ', adresPol.Poczta));
|
||||
}
|
||||
if (adresPol.GLN) {
|
||||
result.push(createLabelText('GLN: ', adresPol.GLN));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
47
src/lib-public/generators/FA1/DodatkoweInformacje.spec.ts
Normal file
47
src/lib-public/generators/FA1/DodatkoweInformacje.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { DodatkowyOpi, Fa } from '../../types/fa1.types';
|
||||
import { generateDodatkoweInformacje } from './DodatkoweInformacje';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: () => [{ text: 'HEADER:Dodatkowe informacje' }],
|
||||
createSubHeader: () => [{ text: 'SUBHEADER:Dodatkowy opis' }],
|
||||
formatText: (text: string) => ({ text }),
|
||||
createSection: (content: any, _: boolean) => content,
|
||||
getValue: (val: any) => val?._text || '',
|
||||
getTable: (data: any) => data,
|
||||
getContentTable: () => ({ content: { table: 'FAKE_TABLE' } }),
|
||||
}));
|
||||
|
||||
describe('generateDodatkoweInformacje', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('returns an empty array when no triggers present', () => {
|
||||
const faVat: Fa = {};
|
||||
const result = generateDodatkoweInformacje(faVat);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns correct table when DodatkowyOpis provided', () => {
|
||||
const faVat: Fa = {
|
||||
DodatkowyOpis: [
|
||||
{ Klucz: { _text: 'RODZAJ' }, Wartosc: { _text: 'TRESC' } },
|
||||
{ Klucz: { _text: 'INNY' }, Wartosc: { _text: 'OPIS' } },
|
||||
] as DodatkowyOpi[],
|
||||
};
|
||||
const result = generateDodatkoweInformacje(faVat);
|
||||
|
||||
expect(result).toContainEqual({ text: 'HEADER:Dodatkowe informacje' });
|
||||
expect(result).toContainEqual({ text: 'SUBHEADER:Dodatkowy opis' });
|
||||
expect(result).toContainEqual({ table: 'FAKE_TABLE' });
|
||||
});
|
||||
|
||||
it('includes section when any element is present', () => {
|
||||
const faVat: Fa = { TP: { _text: '1' }, ZwrotAkcyzy: { _text: '1' } };
|
||||
const result = generateDodatkoweInformacje(faVat);
|
||||
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
87
src/lib-public/generators/FA1/DodatkoweInformacje.ts
Normal file
87
src/lib-public/generators/FA1/DodatkoweInformacje.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createSection,
|
||||
createSubHeader,
|
||||
formatText,
|
||||
getContentTable,
|
||||
getTable,
|
||||
getValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { DodatkowyOpi, Fa } from '../../types/fa1.types';
|
||||
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[] = [];
|
||||
|
||||
if (getValue(faVat.TP) === '1') {
|
||||
tpLabel1.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 zwrotAkcyzyLabel: Content[] = [];
|
||||
|
||||
if (getValue(faVat.ZwrotAkcyzy) === '1') {
|
||||
zwrotAkcyzyLabel.push(
|
||||
formatText(
|
||||
'- Informacja dodatkowa związana ze zwrotem podatku akcyzowego zawartego w cenie oleju napędowego'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const labels: Content[][] = [tpLabel1, tpLabel2, zwrotAkcyzyLabel].filter((el) => el.length > 0);
|
||||
const table: Content[] = [
|
||||
...createHeader('Dodatkowe informacje'),
|
||||
...labels,
|
||||
...generateDodatkowyOpis(faVat.DodatkowyOpis),
|
||||
];
|
||||
|
||||
return table.length > 1 ? createSection(table, true) : [];
|
||||
}
|
||||
|
||||
function generateDodatkowyOpis(fakturaZaliczkowaData: DodatkowyOpi[] | undefined): Content[] {
|
||||
if (!fakturaZaliczkowaData) {
|
||||
return [];
|
||||
}
|
||||
const fakturaZaliczkowa: FakturaZaliczkowa[] = getTable(fakturaZaliczkowaData)?.map((item, index) => ({
|
||||
...item,
|
||||
lp: { _text: index + 1 },
|
||||
}));
|
||||
const table: Content[] = createSubHeader('Dodatkowy opis');
|
||||
|
||||
const fakturaZaliczkowaHeader: HeaderDefine[] = [
|
||||
{
|
||||
name: 'lp',
|
||||
title: 'Lp.',
|
||||
format: FormatTyp.Default,
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
name: 'Klucz',
|
||||
title: 'Rodzaj informacji',
|
||||
format: FormatTyp.Default,
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
name: 'Wartosc',
|
||||
title: 'Treść informacji',
|
||||
format: FormatTyp.Default,
|
||||
width: '*',
|
||||
},
|
||||
];
|
||||
const tableFakturaZaliczkowa: TableWithFields = getContentTable<(typeof fakturaZaliczkowa)[0]>(
|
||||
fakturaZaliczkowaHeader,
|
||||
fakturaZaliczkowa,
|
||||
'*',
|
||||
[0, 0, 0, 0]
|
||||
);
|
||||
|
||||
if (tableFakturaZaliczkowa.content) {
|
||||
table.push(tableFakturaZaliczkowa.content);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
122
src/lib-public/generators/FA1/Platnosc.spec.ts
Normal file
122
src/lib-public/generators/FA1/Platnosc.spec.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generatePlatnosc } from './Platnosc';
|
||||
import { Platnosc } from '../../types/fa1.types';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((label: string, _pad?: any) => [{ text: `HEADER:${label}` }]),
|
||||
createLabelText: vi.fn((label: string, value: any) => ({
|
||||
text: `LABEL:${label}${typeof value === 'object' && value?._text ? value._text : value}`,
|
||||
})),
|
||||
generateLine: vi.fn(() => ({ text: 'LINE' })),
|
||||
generateTwoColumns: vi.fn((left, right, pad?) => ({ left, right, pad, type: '2COL' })),
|
||||
getContentTable: vi.fn((_header, data, _width) => ({
|
||||
content: Array.isArray(data) && data.length ? { data } : undefined,
|
||||
})),
|
||||
getTable: vi.fn((data) => data || []),
|
||||
hasValue: vi.fn((fp: any) => Boolean(fp && fp._text && fp._text !== '')),
|
||||
}));
|
||||
vi.mock('../../../shared/generators/common/functions', () => ({
|
||||
getFormaPlatnosciString: vi.fn((fp: any) => (fp?._text ? 'Przelew' : '')),
|
||||
}));
|
||||
vi.mock('./RachunekBankowy', () => ({
|
||||
generujRachunekBankowy: vi.fn((table, label) => [{ text: `ACCOUNT:${label}` }]),
|
||||
}));
|
||||
|
||||
describe('generatePlatnosc', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns empty array when no payment info given', () => {
|
||||
expect(generatePlatnosc(undefined)).toEqual([]);
|
||||
});
|
||||
|
||||
it('handles case: Platnosc.Zaplacono = 1', () => {
|
||||
const p: Platnosc = { Zaplacono: { _text: '1' }, DataZaplaty: { _text: '2025-10-10' } };
|
||||
const result = generatePlatnosc(p);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ text: 'LINE' },
|
||||
{ text: 'HEADER:Płatność' },
|
||||
{ text: 'LABEL:Informacja o płatności: Zapłacono' },
|
||||
{ text: 'LABEL:Data zapłaty: 2025-10-10' },
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('handles case: Platnosc.ZaplataCzesciowa = 1', () => {
|
||||
const p: Platnosc = { ZaplataCzesciowa: { _text: '1' } };
|
||||
const result = generatePlatnosc(p);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([{ text: 'LABEL:Informacja o płatności: Zapłata częściowa' }])
|
||||
);
|
||||
});
|
||||
|
||||
it('handles case: not paid', () => {
|
||||
const p: Platnosc = {};
|
||||
const result = generatePlatnosc(p);
|
||||
|
||||
expect(result).toEqual(expect.arrayContaining([{ text: 'LABEL:Informacja o płatności: Brak zapłaty' }]));
|
||||
});
|
||||
|
||||
it('adds "Forma płatności" with getFormaPlatnosciString when present', () => {
|
||||
const p: Platnosc = { FormaPlatnosci: { _text: '1' } };
|
||||
const result = generatePlatnosc(p);
|
||||
|
||||
expect(result).toEqual(expect.arrayContaining([{ text: 'LABEL:Forma płatności: Przelew' }]));
|
||||
});
|
||||
|
||||
it('falls back on "Brak zapłaty" and inna/opis if FormaPlatnosci undefined but OpisPlatnosci present', () => {
|
||||
const p: Platnosc = { OpisPlatnosci: { _text: 'Gotówka przy odbiorze' } };
|
||||
const result = generatePlatnosc(p);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ text: 'LABEL:Informacja o płatności: Brak zapłaty' },
|
||||
{ text: 'LABEL:Forma płatności: Płatność inna' },
|
||||
{ text: 'LABEL:Opis płatności innej: Gotówka przy odbiorze' },
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('renders tables for partials and terms if present', () => {
|
||||
const p: Platnosc = {
|
||||
PlatnosciCzesciowe: [
|
||||
{ DataZaplatyCzesciowej: { _text: '2025-01-01' }, KwotaZaplatyCzesciowej: { _text: '100' } },
|
||||
],
|
||||
TerminyPlatnosci: [
|
||||
{ TerminPlatnosci: { _text: '2025-02-01' }, TerminPlatnosciOpis: { _text: 'Do miesiąca' } },
|
||||
],
|
||||
};
|
||||
const result: any = generatePlatnosc(p);
|
||||
|
||||
expect(result.some((el: any) => el.type === '2COL')).toBe(true);
|
||||
});
|
||||
|
||||
it('renders Skonto info if present', () => {
|
||||
const p: Platnosc = { Skonto: { WarunkiSkonta: { _text: '30 dni' }, WysokoscSkonta: { _text: '5%' } } };
|
||||
const result = generatePlatnosc(p);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([
|
||||
[{ text: 'HEADER:Skonto' }],
|
||||
{ text: 'LABEL:Warunki skonta: 30 dni' },
|
||||
{ text: 'LABEL:Wysokość skonta: 5%' },
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('always outputs column with bank accounts', () => {
|
||||
const p: Platnosc = { RachunekBankowy: [{}], RachunekBankowyFaktora: [{}] };
|
||||
const result: any = generatePlatnosc(p);
|
||||
const accCol = result.find(
|
||||
(el: any) =>
|
||||
Array.isArray(el.left) &&
|
||||
Array.isArray(el.right) &&
|
||||
el.left[0]?.text?.startsWith('ACCOUNT:') &&
|
||||
el.right[0]?.text?.startsWith('ACCOUNT:')
|
||||
);
|
||||
|
||||
expect(accCol).toBeTruthy();
|
||||
});
|
||||
});
|
||||
128
src/lib-public/generators/FA1/Platnosc.ts
Normal file
128
src/lib-public/generators/FA1/Platnosc.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
generateLine,
|
||||
generateTwoColumns,
|
||||
getContentTable,
|
||||
getTable,
|
||||
hasValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { FP, Platnosc, PlatnosciCzesciowe, TerminyPlatnosci } from '../../types/fa1.types';
|
||||
import { getFormaPlatnosciString } from '../../../shared/generators/common/functions';
|
||||
import { generujRachunekBankowy } from './RachunekBankowy';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { TableWithFields, TerminPlatnosciContent } from '../../types/fa1-additional-types';
|
||||
|
||||
export function generatePlatnosc(platnosc: Platnosc | undefined): Content {
|
||||
if (!platnosc) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const terminPlatnosci: TerminyPlatnosci[] = getTable(platnosc.TerminyPlatnosci);
|
||||
|
||||
const zaplataCzesciowaHeader: HeaderDefine[] = [
|
||||
{
|
||||
name: 'TerminPlatnosci',
|
||||
title: 'Termin płatności',
|
||||
format: FormatTyp.Default,
|
||||
},
|
||||
];
|
||||
|
||||
if (terminPlatnosci.some((termin: TerminyPlatnosci): FP | undefined => termin.TerminPlatnosciOpis)) {
|
||||
zaplataCzesciowaHeader.push({
|
||||
name: 'TerminPlatnosciOpis',
|
||||
title: 'Opis płatności',
|
||||
format: FormatTyp.Default,
|
||||
});
|
||||
}
|
||||
|
||||
const zaplataCzesciowaNaglowek: HeaderDefine[] = [
|
||||
{
|
||||
name: 'DataZaplatyCzesciowej',
|
||||
title: 'Data zapłaty częściowej',
|
||||
format: FormatTyp.Default,
|
||||
},
|
||||
{ name: 'KwotaZaplatyCzesciowej', title: 'Kwota zapłaty częściowej', format: FormatTyp.Currency },
|
||||
{ name: 'FormaPlatnosci', title: 'Forma płatności', format: FormatTyp.FormOfPayment },
|
||||
];
|
||||
|
||||
const table: Content[] = [generateLine(), ...createHeader('Płatność')];
|
||||
|
||||
if (platnosc.Zaplacono?._text === '1') {
|
||||
table.push(createLabelText('Informacja o płatności: ', 'Zapłacono'));
|
||||
table.push(createLabelText('Data zapłaty: ', platnosc.DataZaplaty));
|
||||
} else if (platnosc.ZaplataCzesciowa?._text === '1') {
|
||||
table.push(createLabelText('Informacja o płatności: ', 'Zapłata częściowa'));
|
||||
} else {
|
||||
table.push(createLabelText('Informacja o płatności: ', 'Brak zapłaty'));
|
||||
}
|
||||
|
||||
if (hasValue(platnosc.FormaPlatnosci)) {
|
||||
table.push(createLabelText('Forma płatności: ', getFormaPlatnosciString(platnosc.FormaPlatnosci)));
|
||||
} else {
|
||||
if (platnosc.OpisPlatnosci?._text) {
|
||||
table.push(createLabelText('Forma płatności: ', 'Płatność inna'));
|
||||
table.push(createLabelText('Opis płatności innej: ', platnosc.OpisPlatnosci));
|
||||
}
|
||||
}
|
||||
|
||||
const zaplataCzesciowa: PlatnosciCzesciowe[] = getTable(platnosc.PlatnosciCzesciowe);
|
||||
const tableZaplataCzesciowa: TableWithFields = getContentTable<(typeof zaplataCzesciowa)[0]>(
|
||||
zaplataCzesciowaNaglowek,
|
||||
zaplataCzesciowa,
|
||||
'*'
|
||||
);
|
||||
|
||||
const terminPatnosciContent: (TerminyPlatnosci | TerminPlatnosciContent)[] = terminPlatnosci.map(
|
||||
(platnosc: TerminyPlatnosci): TerminyPlatnosci | TerminPlatnosciContent => {
|
||||
if (!terminPlatnosci.some((termin: TerminyPlatnosci): FP | undefined => termin.TerminPlatnosciOpis)) {
|
||||
return platnosc;
|
||||
} else {
|
||||
return {
|
||||
...platnosc,
|
||||
TerminPlatnosciOpis: {
|
||||
_text: `${platnosc.TerminPlatnosciOpis?._text ?? ''}`,
|
||||
} as any,
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const tableTerminPlatnosci = getContentTable<(typeof terminPlatnosci)[0]>(
|
||||
zaplataCzesciowaHeader,
|
||||
terminPatnosciContent as TerminyPlatnosci[],
|
||||
'*'
|
||||
);
|
||||
|
||||
if (zaplataCzesciowa.length > 0 && terminPlatnosci.length > 0) {
|
||||
table.push(
|
||||
generateTwoColumns(
|
||||
tableZaplataCzesciowa.content ?? [],
|
||||
tableTerminPlatnosci.content ?? [],
|
||||
[0, 4, 0, 0]
|
||||
)
|
||||
);
|
||||
} else if (terminPlatnosci.length > 0) {
|
||||
if (tableTerminPlatnosci.content) {
|
||||
table.push(generateTwoColumns([], tableTerminPlatnosci.content));
|
||||
}
|
||||
} else if (zaplataCzesciowa.length > 0 && tableZaplataCzesciowa.content) {
|
||||
table.push(tableZaplataCzesciowa.content);
|
||||
}
|
||||
|
||||
table.push(
|
||||
generateTwoColumns(
|
||||
generujRachunekBankowy(getTable(platnosc.RachunekBankowy), 'Numer rachunku bankowego'),
|
||||
generujRachunekBankowy(getTable(platnosc.RachunekBankowyFaktora), 'Numer rachunku bankowego faktora')
|
||||
)
|
||||
);
|
||||
|
||||
if (platnosc.Skonto) {
|
||||
table.push(createHeader('Skonto', [0, 0]));
|
||||
table.push(createLabelText('Warunki skonta: ', platnosc.Skonto.WarunkiSkonta));
|
||||
table.push(createLabelText('Wysokość skonta: ', platnosc.Skonto.WysokoscSkonta));
|
||||
}
|
||||
return table;
|
||||
}
|
||||
92
src/lib-public/generators/FA1/Podmiot1.spec.ts
Normal file
92
src/lib-public/generators/FA1/Podmiot1.spec.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { Podmiot1 } from '../../types/fa1.types';
|
||||
import { generatePodmiot1 } from './Podmiot1';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((label: string) => [{ text: `HEADER:${label}` }]),
|
||||
createLabelText: vi.fn((label: string, value: any) => ({
|
||||
text: `LABEL:${label}${typeof value === 'object' && value?._text ? value._text : value}`,
|
||||
})),
|
||||
formatText: vi.fn((text: string, _args?: any) => ({ text: `FMT:${text}` })),
|
||||
getTable: vi.fn((data) => data || []),
|
||||
}));
|
||||
vi.mock('./PodmiotAdres', () => ({
|
||||
generatePodmiotAdres: vi.fn((adres: any, label: string) => ({ adr: `${label}` })),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjne', () => ({
|
||||
generateDaneIdentyfikacyjne: vi.fn((daneId: any) => [{ id: 'ID' }]),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneKontaktowe', () => ({
|
||||
generateDaneKontaktowe: vi.fn((email: any, tel: any) => [{ contact: 'KONTAKT' }]),
|
||||
}));
|
||||
|
||||
describe('generatePodmiot1', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('renders header and base labels', () => {
|
||||
const podmiot1: Podmiot1 = {
|
||||
NrEORI: { _text: 'EORI123' },
|
||||
PrefiksPodatnika: { _text: 'PL' },
|
||||
};
|
||||
const result = generatePodmiot1(podmiot1);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ text: 'HEADER:Sprzedawca' },
|
||||
{ text: 'LABEL:NrEORI: EORI123' },
|
||||
{ text: 'LABEL:Prefiks VAT: PL' },
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('calls generateDaneIdentyfikacyjne when present', () => {
|
||||
const podmiot1: Podmiot1 = {
|
||||
DaneIdentyfikacyjne: { NIP: { _text: '1234' } },
|
||||
NrEORI: { _text: 'xxx' },
|
||||
PrefiksPodatnika: { _text: 'PL' },
|
||||
};
|
||||
const result = generatePodmiot1(podmiot1);
|
||||
|
||||
expect(result).toEqual(expect.arrayContaining([{ id: 'ID' }]));
|
||||
});
|
||||
|
||||
it('renders PodmiotAdres if adres present', () => {
|
||||
const podmiot1: Podmiot1 = {
|
||||
NrEORI: { _text: 'xxx' },
|
||||
PrefiksPodatnika: { _text: 'PL' },
|
||||
Adres: { AdresPol: { Miasto: { _text: 'Katowice' } } },
|
||||
};
|
||||
const result = generatePodmiot1(podmiot1);
|
||||
|
||||
expect(result).toEqual(expect.arrayContaining([{ adr: 'Adres' }]));
|
||||
});
|
||||
|
||||
it('renders contact section and status if Email/Telefon present', () => {
|
||||
const podmiot1: Podmiot1 = {
|
||||
NrEORI: { _text: 'xxx' },
|
||||
PrefiksPodatnika: { _text: 'PL' },
|
||||
Email: { _text: 'a@b.pl' },
|
||||
StatusInfoPodatnika: { _text: 'zarejestrowany' },
|
||||
};
|
||||
const result = generatePodmiot1(podmiot1);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ text: 'FMT:Dane kontaktowe' },
|
||||
{ contact: 'KONTAKT' },
|
||||
{ text: 'LABEL:Status podatnika: zarejestrowany' },
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('renders only status if no Email/Telefon but StatusInfoPodatnika present', () => {
|
||||
const podmiot1: Podmiot1 = {
|
||||
NrEORI: { _text: 'xxx' },
|
||||
PrefiksPodatnika: { _text: 'PL' },
|
||||
StatusInfoPodatnika: { _text: 'SAMO' },
|
||||
};
|
||||
const result = generatePodmiot1(podmiot1);
|
||||
|
||||
expect(result).toEqual(expect.arrayContaining([{ text: 'LABEL:Status podatnika: SAMO' }]));
|
||||
});
|
||||
});
|
||||
39
src/lib-public/generators/FA1/Podmiot1.ts
Normal file
39
src/lib-public/generators/FA1/Podmiot1.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { createHeader, createLabelText, formatText, getTable } 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';
|
||||
|
||||
export function generatePodmiot1(podmiot1: Podmiot1): Content[] {
|
||||
const result: Content[] = createHeader('Sprzedawca');
|
||||
|
||||
result.push(
|
||||
createLabelText('NrEORI: ', podmiot1.NrEORI),
|
||||
createLabelText('Prefiks VAT: ', podmiot1.PrefiksPodatnika)
|
||||
);
|
||||
if (podmiot1.DaneIdentyfikacyjne) {
|
||||
result.push(...generateDaneIdentyfikacyjne(podmiot1.DaneIdentyfikacyjne));
|
||||
}
|
||||
|
||||
if (podmiot1.Adres) {
|
||||
result.push(generatePodmiotAdres(podmiot1.Adres, 'Adres', true, [0, 12, 0, 1.3]));
|
||||
}
|
||||
if (podmiot1.AdresKoresp) {
|
||||
result.push(
|
||||
...generatePodmiotAdres(podmiot1.AdresKoresp, 'Adres do korespondencji', true, [0, 12, 0, 1.3])
|
||||
);
|
||||
}
|
||||
if (podmiot1.Email || podmiot1.Telefon) {
|
||||
result.push(
|
||||
formatText('Dane kontaktowe', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
...generateDaneKontaktowe(podmiot1.Email, getTable(podmiot1.Telefon))
|
||||
);
|
||||
|
||||
result.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika));
|
||||
} else if (podmiot1.StatusInfoPodatnika) {
|
||||
result.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
67
src/lib-public/generators/FA1/Podmiot1Podmiot1K.spec.ts
Normal file
67
src/lib-public/generators/FA1/Podmiot1Podmiot1K.spec.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { Podmiot1, Podmiot1K } from '../../types/fa1.types';
|
||||
import { generatePodmiot1Podmiot1K } from './Podmiot1Podmiot1K';
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((label: string) => [{ text: `HEADER:${label}` }]),
|
||||
createLabelText: vi.fn((label: string, value: any) => ({
|
||||
text: `LABEL:${label}${value && value._text ? value._text : value}`,
|
||||
})),
|
||||
createSubHeader: vi.fn((label: string) => ({ text: `SUBHEADER:${label}` })),
|
||||
verticalSpacing: vi.fn((v: number) => ({ text: `SPACING:${v}` })),
|
||||
getTable: vi.fn((data) => data || []),
|
||||
}));
|
||||
vi.mock('./PodmiotAdres', () => ({
|
||||
generatePodmiotAdres: vi.fn((adres: any, label: string) => ({ adr: label })),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjne', () => ({
|
||||
generateDaneIdentyfikacyjne: vi.fn(() => [{ id: 'ID' }]),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneKontaktowe', () => ({
|
||||
generateDaneKontaktowe: vi.fn(() => ({ contact: 'KONTAKT' })),
|
||||
}));
|
||||
|
||||
describe('generatePodmiot1Podmiot1K', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('puts DaneIdentyfikacyjne & status in firstColumn', () => {
|
||||
const podmiot1: Podmiot1 = {
|
||||
NrEORI: { _text: 'EORI' },
|
||||
DaneIdentyfikacyjne: { NIP: { _text: '777' } },
|
||||
StatusInfoPodatnika: { _text: 'AKTYWNY' },
|
||||
};
|
||||
const podmiot1K: Podmiot1K = {};
|
||||
const result: any = generatePodmiot1Podmiot1K(podmiot1, podmiot1K);
|
||||
const firstCol: Content = result.find((r: any) => r.columns)?.columns[0];
|
||||
|
||||
expect(firstCol).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ text: 'SUBHEADER:Dane identyfikacyjne' },
|
||||
{ text: 'LABEL:Numer EORI: EORI' },
|
||||
{ id: 'ID' },
|
||||
{ text: 'LABEL:Status podatnika: AKTYWNY' },
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('adds contact if Email present', () => {
|
||||
const podmiot1: Podmiot1 = {
|
||||
NrEORI: { _text: 'EORI' },
|
||||
Email: { _text: 'mail@ex.pl' },
|
||||
};
|
||||
const podmiot1K: Podmiot1K = {};
|
||||
const result: any = generatePodmiot1Podmiot1K(podmiot1, podmiot1K);
|
||||
const firstCol: Content = result.find((r: any) => r.columns)?.columns[0];
|
||||
|
||||
expect(firstCol).toEqual(expect.arrayContaining([{ contact: 'KONTAKT' }]));
|
||||
});
|
||||
|
||||
it('adds verticalSpacing at the end', () => {
|
||||
const podmiot1: Podmiot1 = { NrEORI: { _text: 'EORI' } };
|
||||
const podmiot1K: Podmiot1K = {};
|
||||
const result: Content[] = generatePodmiot1Podmiot1K(podmiot1, podmiot1K);
|
||||
|
||||
expect(result[result.length - 1]).toEqual({ text: 'SPACING:1' });
|
||||
});
|
||||
});
|
||||
71
src/lib-public/generators/FA1/Podmiot1Podmiot1K.ts
Normal file
71
src/lib-public/generators/FA1/Podmiot1Podmiot1K.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
createSubHeader,
|
||||
getTable,
|
||||
verticalSpacing,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { Podmiot1, Podmiot1K } from '../../types/fa1.types';
|
||||
import { generatePodmiotAdres } from './PodmiotAdres';
|
||||
import { generateDaneIdentyfikacyjne } from './PodmiotDaneIdentyfikacyjne';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
|
||||
export function generatePodmiot1Podmiot1K(podmiot1: Podmiot1, podmiot1K: Podmiot1K): Content[] {
|
||||
const result: Content[] = createHeader('Sprzedawca');
|
||||
let firstColumn: Content[] = [];
|
||||
let secondColumn: Content[] = [];
|
||||
|
||||
firstColumn.push(createSubHeader('Dane identyfikacyjne'), createLabelText('Numer EORI: ', podmiot1.NrEORI));
|
||||
if (podmiot1.DaneIdentyfikacyjne) {
|
||||
firstColumn.push(...generateDaneIdentyfikacyjne(podmiot1.DaneIdentyfikacyjne));
|
||||
}
|
||||
|
||||
if (podmiot1.Email || podmiot1.Telefon) {
|
||||
firstColumn.push(generateDaneKontaktowe(podmiot1.Email, getTable(podmiot1.Telefon)));
|
||||
}
|
||||
if (podmiot1.StatusInfoPodatnika) {
|
||||
firstColumn.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika));
|
||||
}
|
||||
if (firstColumn.length) {
|
||||
result.push({
|
||||
columns: [firstColumn, []],
|
||||
columnGap: 20,
|
||||
});
|
||||
}
|
||||
firstColumn = generateCorrectedContent(podmiot1K, 'Treść korygowana');
|
||||
secondColumn = generateCorrectedContent(podmiot1, 'Treść korygująca');
|
||||
|
||||
if (podmiot1.AdresKoresp) {
|
||||
secondColumn.push(
|
||||
generatePodmiotAdres(podmiot1.AdresKoresp, 'Adres do korespondencji', true, [0, 12, 0, 1.3])
|
||||
);
|
||||
}
|
||||
if (firstColumn.length || secondColumn.length) {
|
||||
result.push({
|
||||
columns: [firstColumn, secondColumn],
|
||||
columnGap: 20,
|
||||
});
|
||||
}
|
||||
if (result.length) {
|
||||
result.push(verticalSpacing(1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function generateCorrectedContent(podmiot: Podmiot1 | Podmiot1K, headerText: string): Content[] {
|
||||
const result: Content[] = [];
|
||||
|
||||
result.push(createSubHeader(headerText));
|
||||
|
||||
if (podmiot.PrefiksPodatnika?._text) {
|
||||
result.push(createLabelText('Prefiks VAT: ', podmiot.PrefiksPodatnika));
|
||||
}
|
||||
if (podmiot.DaneIdentyfikacyjne) {
|
||||
result.push(...generateDaneIdentyfikacyjne(podmiot.DaneIdentyfikacyjne));
|
||||
}
|
||||
if (podmiot.Adres) {
|
||||
result.push(generatePodmiotAdres(podmiot.Adres, 'Adres', true, [0, 12, 0, 1.3]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
68
src/lib-public/generators/FA1/Podmiot2.spec.ts
Normal file
68
src/lib-public/generators/FA1/Podmiot2.spec.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { Podmiot2 } from '../../types/fa1.types';
|
||||
import { generatePodmiot2 } from './Podmiot2';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((label: string) => [{ text: `HEADER:${label}` }]),
|
||||
createLabelText: vi.fn((label: string, value: any) => ({
|
||||
text: `LABEL:${label}${typeof value === 'object' && value?._text ? value._text : value}`,
|
||||
})),
|
||||
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 })),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjne', () => ({
|
||||
generateDaneIdentyfikacyjne: vi.fn(() => [{ id: 'ID' }]),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneKontaktowe', () => ({
|
||||
generateDaneKontaktowe: vi.fn(() => [{ contact: 'KONTAKT' }]),
|
||||
}));
|
||||
|
||||
describe('generatePodmiot2', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('renders header and base fields', () => {
|
||||
const podmiot2: Podmiot2 = {
|
||||
NrEORI: { _text: 'EORI777' },
|
||||
};
|
||||
const result = generatePodmiot2(podmiot2);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([{ text: 'HEADER:Nabywca' }, { text: 'LABEL:NrEORI: EORI777' }])
|
||||
);
|
||||
});
|
||||
|
||||
it('adds PrefiksNabywcy if hasValue true', () => {
|
||||
const podmiot2: Podmiot2 = {
|
||||
NrEORI: { _text: 'EORI1' },
|
||||
PrefiksNabywcy: { _text: 'PN1' },
|
||||
};
|
||||
const result = generatePodmiot2(podmiot2);
|
||||
|
||||
expect(result).toEqual(expect.arrayContaining([{ text: 'LABEL:Prefiks VAT: PN1' }]));
|
||||
});
|
||||
|
||||
it('includes contact info when Email or Telefon present', () => {
|
||||
const podmiot2: Podmiot2 = {
|
||||
NrEORI: { _text: 'EORI4' },
|
||||
Email: { _text: 'test@mail.com' },
|
||||
};
|
||||
const result = generatePodmiot2(podmiot2);
|
||||
|
||||
expect(result).toEqual(expect.arrayContaining([{ text: 'FMT:Dane kontaktowe' }, { contact: 'KONTAKT' }]));
|
||||
});
|
||||
|
||||
it('includes NrKlienta label if present', () => {
|
||||
const podmiot2: Podmiot2 = {
|
||||
NrEORI: { _text: 'EORI5' },
|
||||
NrKlienta: { _text: 'NR1234' },
|
||||
};
|
||||
const result = generatePodmiot2(podmiot2);
|
||||
|
||||
expect(result).toEqual(expect.arrayContaining([{ text: 'LABEL:Numer klienta: NR1234' }]));
|
||||
});
|
||||
});
|
||||
54
src/lib-public/generators/FA1/Podmiot2.ts
Normal file
54
src/lib-public/generators/FA1/Podmiot2.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
formatText,
|
||||
getTable,
|
||||
getValue,
|
||||
hasValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { Podmiot2 } from '../../types/fa1.types';
|
||||
import { generatePodmiotAdres } from './PodmiotAdres';
|
||||
import { generateDaneIdentyfikacyjne } from './PodmiotDaneIdentyfikacyjne';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
import { DaneIdentyfikacyjneTPodmiot2Dto } from '../../types/fa2-additional-types';
|
||||
|
||||
export function generatePodmiot2(podmiot2: Podmiot2): Content[] {
|
||||
const result: Content[] = createHeader('Nabywca');
|
||||
|
||||
result.push(createLabelText('NrEORI: ', podmiot2.NrEORI));
|
||||
if (hasValue(podmiot2.PrefiksNabywcy)) {
|
||||
result.push(createLabelText('Prefiks VAT: ', podmiot2.PrefiksNabywcy));
|
||||
}
|
||||
if (podmiot2.DaneIdentyfikacyjne) {
|
||||
if (hasValue(podmiot2.DaneIdentyfikacyjne.NrID)) {
|
||||
result.push(createLabelText('Identyfikator podatkowy inny: ', podmiot2.DaneIdentyfikacyjne.NrID));
|
||||
}
|
||||
if (getValue(podmiot2.DaneIdentyfikacyjne.BrakID) === '1') {
|
||||
result.push(createLabelText('Brak identyfikatora ', ' '));
|
||||
}
|
||||
result.push(
|
||||
...generateDaneIdentyfikacyjne(podmiot2.DaneIdentyfikacyjne as DaneIdentyfikacyjneTPodmiot2Dto)
|
||||
);
|
||||
}
|
||||
|
||||
if (podmiot2.Adres) {
|
||||
result.push(generatePodmiotAdres(podmiot2.Adres, 'Adres', true, [0, 12, 0, 1.3]));
|
||||
}
|
||||
if (podmiot2.AdresKoresp) {
|
||||
result.push(
|
||||
...generatePodmiotAdres(podmiot2.AdresKoresp, 'Adres do korespondencji', true, [0, 12, 0, 1.3])
|
||||
);
|
||||
}
|
||||
if (podmiot2.Email || podmiot2.Telefon) {
|
||||
result.push(
|
||||
formatText('Dane kontaktowe', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
...generateDaneKontaktowe(podmiot2.Email, getTable(podmiot2.Telefon))
|
||||
);
|
||||
}
|
||||
if (podmiot2.NrKlienta) {
|
||||
result.push(createLabelText('Numer klienta: ', podmiot2.NrKlienta));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
103
src/lib-public/generators/FA1/Podmiot2Podmiot2k.spec.ts
Normal file
103
src/lib-public/generators/FA1/Podmiot2Podmiot2k.spec.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { Podmiot2, Podmiot2K } from '../../types/fa1.types';
|
||||
import { generatePodmiot2Podmiot2K } from './Podmiot2Podmiot2k';
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((label) => [{ text: `HEADER:${label}` }]),
|
||||
createLabelText: vi.fn((label, value) => ({
|
||||
text: `LABEL:${label}${value && value._text ? value._text : ''}`,
|
||||
})),
|
||||
createSubHeader: vi.fn((label) => ({ text: `SUBHEADER:${label}` })),
|
||||
verticalSpacing: vi.fn((num) => ({ text: `SPACING:${num}` })),
|
||||
getTable: vi.fn((arr) => arr || []),
|
||||
getValue: vi.fn((val) => (val && val._text ? val._text : '')),
|
||||
hasValue: vi.fn((val) => Boolean(val && val._text)),
|
||||
}));
|
||||
vi.mock('./PodmiotAdres', () => ({
|
||||
generatePodmiotAdres: vi.fn((adres, label) => ({ adr: label })),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjne', () => ({
|
||||
generateDaneIdentyfikacyjne: vi.fn(() => [{ id: 'ID' }]),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneKontaktowe', () => ({
|
||||
generateDaneKontaktowe: vi.fn(() => ({ contact: 'KONTAKT' })),
|
||||
}));
|
||||
|
||||
describe('generatePodmiot2Podmiot2K', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
function hasColumns(r: unknown): r is { columns: unknown[] } {
|
||||
return (
|
||||
typeof r === 'object' &&
|
||||
r !== null &&
|
||||
'columns' in r &&
|
||||
Array.isArray((r as { columns: unknown[] }).columns)
|
||||
);
|
||||
}
|
||||
|
||||
it('renders HEADER and at least one columns object', () => {
|
||||
const podmiot2: Podmiot2 = { NrEORI: { _text: 'A' } };
|
||||
const podmiot2K: Podmiot2K = {};
|
||||
const result: Content[] = generatePodmiot2Podmiot2K(podmiot2, podmiot2K);
|
||||
|
||||
expect(result[0]).toEqual({ text: 'HEADER:Nabywca' });
|
||||
expect(
|
||||
result.some((r: Content) => {
|
||||
if (hasColumns(r)) {
|
||||
return Array.isArray(r.columns);
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('builds firstColumn with full data', () => {
|
||||
const podmiot2: Podmiot2 = {
|
||||
NrEORI: { _text: 'EORI-X' },
|
||||
DaneIdentyfikacyjne: { NrID: { _text: 'FOO' } },
|
||||
Email: { _text: 'xx@a.pl' },
|
||||
NrKlienta: { _text: 'CUSTX' },
|
||||
Telefon: [{ _text: '600100200' }],
|
||||
};
|
||||
const podmiot2K: Podmiot2K = {};
|
||||
const result: any = generatePodmiot2Podmiot2K(podmiot2, podmiot2K);
|
||||
const firstCol: Content = result.find(hasColumns)?.columns[0];
|
||||
|
||||
expect(firstCol).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ text: 'SUBHEADER:Dane identyfikacyjne' },
|
||||
{ text: 'LABEL:Numer EORI: EORI-X' },
|
||||
{ id: 'ID' },
|
||||
{ contact: 'KONTAKT' },
|
||||
{ text: 'LABEL:Numer klienta: CUSTX' },
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('renders "corrected content" for both cols', () => {
|
||||
const podmiot2: Podmiot2 = {
|
||||
PrefiksNabywcy: { _text: 'PN2' },
|
||||
DaneIdentyfikacyjne: { BrakID: { _text: '1' }, NrID: { _text: '123' } },
|
||||
Adres: { AdresPol: { Miasto: { _text: 'CITY' } } },
|
||||
};
|
||||
const podmiot2K: Podmiot2K = {
|
||||
PrefiksNabywcy: { _text: 'NNK' },
|
||||
DaneIdentyfikacyjne: { NrID: { _text: 'XYZ' } },
|
||||
Adres: { AdresZagr: { Kraj: { _text: 'UK' } } },
|
||||
};
|
||||
const result: any = generatePodmiot2Podmiot2K(podmiot2, podmiot2K);
|
||||
const cols: Content[] = result.find(hasColumns)?.columns;
|
||||
|
||||
expect(cols[1]).toEqual([]);
|
||||
});
|
||||
|
||||
it('ends with verticalSpacing', () => {
|
||||
const podmiot2: Podmiot2 = { NrEORI: { _text: 'END' } };
|
||||
const podmiot2K: Podmiot2K = {};
|
||||
const result: Content[] = generatePodmiot2Podmiot2K(podmiot2, podmiot2K);
|
||||
|
||||
expect(result[result.length - 1]).toEqual({ text: 'SPACING:1' });
|
||||
});
|
||||
});
|
||||
79
src/lib-public/generators/FA1/Podmiot2Podmiot2k.ts
Normal file
79
src/lib-public/generators/FA1/Podmiot2Podmiot2k.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
createSubHeader,
|
||||
getTable,
|
||||
getValue,
|
||||
hasValue,
|
||||
verticalSpacing,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { Podmiot2, Podmiot2K } from '../../types/fa1.types';
|
||||
import { generatePodmiotAdres } from './PodmiotAdres';
|
||||
import { generateDaneIdentyfikacyjne } from './PodmiotDaneIdentyfikacyjne';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
|
||||
export function generatePodmiot2Podmiot2K(podmiot2: Podmiot2, podmiot2K: Podmiot2K): Content[] {
|
||||
const result: Content[] = createHeader('Nabywca');
|
||||
let firstColumn: Content[] = [];
|
||||
let secondColumn: Content[] = [];
|
||||
|
||||
firstColumn.push(createSubHeader('Dane identyfikacyjne'), createLabelText('Numer EORI: ', podmiot2.NrEORI));
|
||||
if (podmiot2.DaneIdentyfikacyjne) {
|
||||
firstColumn.push(...generateDaneIdentyfikacyjne(podmiot2.DaneIdentyfikacyjne));
|
||||
}
|
||||
|
||||
if (podmiot2.Email || podmiot2.Telefon) {
|
||||
firstColumn.push(generateDaneKontaktowe(podmiot2.Email, getTable(podmiot2.Telefon)));
|
||||
}
|
||||
if (podmiot2.NrKlienta) {
|
||||
firstColumn.push(createLabelText('Numer klienta: ', podmiot2.NrKlienta));
|
||||
}
|
||||
if (firstColumn.length) {
|
||||
result.push({
|
||||
columns: [firstColumn, []],
|
||||
columnGap: 20,
|
||||
});
|
||||
}
|
||||
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])
|
||||
);
|
||||
}
|
||||
|
||||
if (firstColumn.length || secondColumn.length) {
|
||||
result.push({
|
||||
columns: [firstColumn, secondColumn],
|
||||
columnGap: 20,
|
||||
});
|
||||
}
|
||||
if (result.length) {
|
||||
result.push(verticalSpacing(1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function generateCorrectedContent(podmiot: Podmiot2 | Podmiot2K, headerText: string): Content[] {
|
||||
const result: Content[] = [];
|
||||
|
||||
result.push(createSubHeader(headerText));
|
||||
|
||||
if (hasValue(podmiot.PrefiksNabywcy)) {
|
||||
result.push(createLabelText('Prefiks VAT: ', podmiot.PrefiksNabywcy));
|
||||
}
|
||||
if (podmiot.DaneIdentyfikacyjne) {
|
||||
if (hasValue(podmiot.DaneIdentyfikacyjne.NrID)) {
|
||||
result.push(createLabelText('Identyfikator podatkowy inny: ', podmiot.DaneIdentyfikacyjne.NrID));
|
||||
}
|
||||
if (getValue(podmiot.DaneIdentyfikacyjne.BrakID) === '1') {
|
||||
result.push(createLabelText('Brak identyfikatora ', ' '));
|
||||
}
|
||||
result.push(...generateDaneIdentyfikacyjne(podmiot.DaneIdentyfikacyjne));
|
||||
}
|
||||
if (podmiot.Adres) {
|
||||
result.push(generatePodmiotAdres(podmiot.Adres, 'Adres', true, [0, 12, 0, 1.3]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
95
src/lib-public/generators/FA1/Podmiot3.spec.ts
Normal file
95
src/lib-public/generators/FA1/Podmiot3.spec.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { Podmiot3 } from '../../types/fa1.types';
|
||||
import { generatePodmiot3 } from './Podmiot3';
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((label) => [{ text: `HEADER:${label}` }]),
|
||||
createLabelText: vi.fn((label, value) => ({
|
||||
text: `LABEL:${label}${value && value._text ? value._text : (value ?? '')}`,
|
||||
})),
|
||||
createSection: vi.fn((arr) => arr),
|
||||
formatText: vi.fn((txt, _args) => ({ text: `FMT:${txt}` })),
|
||||
generateTwoColumns: vi.fn((left, right) => ({ type: '2COL', left, right })),
|
||||
getTable: vi.fn((arr) => arr || []),
|
||||
getValue: vi.fn((val) => (val && val._text ? val._text : '')),
|
||||
hasValue: vi.fn((val) => !!(val && val._text)),
|
||||
}));
|
||||
vi.mock('../../../shared/generators/common/functions', () => ({
|
||||
getRolaString: vi.fn((rola, idx) => (rola && rola._text ? 'SPRZEDAWCA' : '')),
|
||||
}));
|
||||
vi.mock('./PodmiotAdres', () => ({
|
||||
generatePodmiotAdres: vi.fn((adres, label) => ({ adr: label })),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjne', () => ({
|
||||
generateDaneIdentyfikacyjne: vi.fn(() => [{ id: 'ID' }]),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneKontaktowe', () => ({
|
||||
generateDaneKontaktowe: vi.fn(() => [{ contact: 'KONTAKT' }]),
|
||||
}));
|
||||
|
||||
describe('generatePodmiot3', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('renders minimal column structure', () => {
|
||||
const podmiot: Podmiot3 = { NrEORI: { _text: '999' }, Rola: { _text: 'X' } };
|
||||
const result: Content[] = generatePodmiot3(podmiot, 0);
|
||||
const last: any = result[result.length - 1] || {};
|
||||
|
||||
expect(last.type).toBe('2COL');
|
||||
expect(last.left).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ text: 'HEADER:Podmiot inny 1' },
|
||||
{ text: 'LABEL:NrEORI: 999' },
|
||||
[{ text: 'LABEL:Rola: SPRZEDAWCA' }, { text: 'LABEL:Rola inna: ' }, { text: 'LABEL:Udział: ' }],
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('renders column1 with all tax ID and role info', () => {
|
||||
const podmiot: Podmiot3 = {
|
||||
NrEORI: { _text: '1000' },
|
||||
DaneIdentyfikacyjne: { NrID: { _text: 'TAXX' }, BrakID: { _text: '1' } },
|
||||
Rola: { _text: 'S' },
|
||||
OpisRoli: { _text: 'operator' },
|
||||
Udzial: { _text: '50%' },
|
||||
};
|
||||
const result: any = generatePodmiot3(podmiot, 1);
|
||||
const col1: Content = result[result.length - 1].left;
|
||||
|
||||
expect(col1).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ text: 'HEADER:Podmiot inny 2' },
|
||||
{ text: 'LABEL:NrEORI: 1000' },
|
||||
{ text: 'LABEL:Identyfikator podatkowy inny: TAXX' },
|
||||
{ text: 'LABEL:Brak identyfikatora ' },
|
||||
{ id: 'ID' },
|
||||
[
|
||||
{ text: 'LABEL:Rola: SPRZEDAWCA' },
|
||||
{ text: 'LABEL:Rola inna: operator' },
|
||||
{ text: 'LABEL:Udział: 50%' },
|
||||
],
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('adds Numer klienta in right column if present', () => {
|
||||
const podmiot: Podmiot3 = {
|
||||
NrEORI: { _text: 'foo' },
|
||||
Rola: { _text: 'ROLA' },
|
||||
NrKlienta: { _text: 'KLIENTX' },
|
||||
};
|
||||
const result: any = generatePodmiot3(podmiot, 2);
|
||||
const col2: Content = result[result.length - 1].right;
|
||||
|
||||
expect(col2).toEqual(expect.arrayContaining([{ text: 'LABEL:Numer klienta: KLIENTX' }]));
|
||||
});
|
||||
|
||||
it('always returns results wrapped in sections', () => {
|
||||
const podmiot: Podmiot3 = { NrEORI: { _text: 'A' }, Rola: { _text: 'B' } };
|
||||
const result: any = generatePodmiot3(podmiot, 1);
|
||||
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result.some((r: any) => r.type === '2COL')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
62
src/lib-public/generators/FA1/Podmiot3.ts
Normal file
62
src/lib-public/generators/FA1/Podmiot3.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
createSection,
|
||||
formatText,
|
||||
generateTwoColumns,
|
||||
getTable,
|
||||
getValue,
|
||||
hasValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { Podmiot3 } from '../../types/fa1.types';
|
||||
import { getRolaString } from '../../../shared/generators/common/functions';
|
||||
import { generatePodmiotAdres } from './PodmiotAdres';
|
||||
import { generateDaneIdentyfikacyjne } from './PodmiotDaneIdentyfikacyjne';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
|
||||
export function generatePodmiot3(podmiot: Podmiot3, index: number): Content[] {
|
||||
const result: Content[] = [];
|
||||
|
||||
const column1: Content[] = [
|
||||
...createHeader(`Podmiot inny ${index + 1}`),
|
||||
createLabelText('NrEORI: ', podmiot.NrEORI),
|
||||
];
|
||||
|
||||
if (hasValue(podmiot.DaneIdentyfikacyjne?.NrID)) {
|
||||
column1.push(createLabelText('Identyfikator podatkowy inny: ', podmiot.DaneIdentyfikacyjne?.NrID));
|
||||
}
|
||||
if (getValue(podmiot.DaneIdentyfikacyjne?.BrakID) === '1') {
|
||||
column1.push(createLabelText('Brak identyfikatora ', ' '));
|
||||
}
|
||||
if (podmiot.DaneIdentyfikacyjne) {
|
||||
column1.push(...generateDaneIdentyfikacyjne(podmiot.DaneIdentyfikacyjne));
|
||||
}
|
||||
column1.push([
|
||||
createLabelText('Rola: ', getRolaString(podmiot.Rola, 1)),
|
||||
createLabelText('Rola inna: ', podmiot.OpisRoli),
|
||||
createLabelText('Udział: ', podmiot.Udzial, [FormatTyp.Percentage]),
|
||||
]);
|
||||
const column2: Content[] = [];
|
||||
|
||||
if (podmiot.Adres) {
|
||||
column2.push(generatePodmiotAdres(podmiot.Adres, 'Adres', true, [0, 12, 0, 1.3]));
|
||||
}
|
||||
if (podmiot.AdresKoresp) {
|
||||
column2.push(
|
||||
...generatePodmiotAdres(podmiot.AdresKoresp, 'Adres do korespondencji', true, [0, 12, 0, 1.3])
|
||||
);
|
||||
}
|
||||
if (podmiot.Email || podmiot.Telefon) {
|
||||
column2.push(
|
||||
formatText('Dane kontaktowe', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
...generateDaneKontaktowe(podmiot.Email, getTable(podmiot.Telefon))
|
||||
);
|
||||
}
|
||||
if (podmiot.NrKlienta) {
|
||||
column2.push(createLabelText('Numer klienta: ', podmiot.NrKlienta));
|
||||
}
|
||||
result.push(generateTwoColumns(column1, column2));
|
||||
return createSection(result, true);
|
||||
}
|
||||
83
src/lib-public/generators/FA1/Podmiot3Podmiot2k.spec.ts
Normal file
83
src/lib-public/generators/FA1/Podmiot3Podmiot2k.spec.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot3Dto } from './Podmiot3Podmiot2k';
|
||||
import { Podmiot3Podmiot2KDto } from '../../types/fa1-additional-types';
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((label) => [{ text: `HEADER:${label}` }]),
|
||||
createLabelText: vi.fn((label, value) => ({
|
||||
text: `LABEL:${label}${value && value._text ? value._text : (value ?? '')}`,
|
||||
})),
|
||||
createSubHeader: vi.fn((label) => [{ text: `SUBHEADER:${label}` }]),
|
||||
generateTwoColumns: vi.fn((left, right) => ({ type: '2COL', left, right })),
|
||||
getTable: vi.fn((arr) => arr || []),
|
||||
getValue: vi.fn((val) => (val && val._text ? val._text : '')),
|
||||
hasValue: vi.fn((val) => !!(val && val._text)),
|
||||
}));
|
||||
vi.mock('../../../shared/generators/common/functions', () => ({
|
||||
getRolaString: vi.fn((rola) => (rola && rola._text ? 'SPRZEDAWCA' : '')),
|
||||
}));
|
||||
vi.mock('./PodmiotAdres', () => ({
|
||||
generatePodmiotAdres: vi.fn((adres, label) => ({ adr: label })),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjne', () => ({
|
||||
generateDaneIdentyfikacyjne: vi.fn(() => [{ id: 'ID' }]),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneKontaktowe', () => ({
|
||||
generateDaneKontaktowe: vi.fn(() => ({ contact: 'KONTAKT' })),
|
||||
}));
|
||||
|
||||
describe('generateDaneIdentyfikacyjneTPodmiot3Dto', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns empty array for undefined input', () => {
|
||||
expect(generateDaneIdentyfikacyjneTPodmiot3Dto(undefined, 0)).toEqual([]);
|
||||
});
|
||||
|
||||
it('creates header and main fields for full identification', () => {
|
||||
const podmiot2KDto: Podmiot3Podmiot2KDto = {
|
||||
fakturaPodmiotNDto: {
|
||||
NrEORI: { _text: 'EXX' },
|
||||
Rola: { _text: 'SPRZEDAWCA' },
|
||||
OpisRoli: { _text: 'rola inna' },
|
||||
Udzial: { _text: '51%' },
|
||||
Email: { _text: 'a@b.pl' },
|
||||
NrKlienta: { _text: 'KLIENTX' },
|
||||
DaneIdentyfikacyjne: { NrID: { _text: 'TID' } },
|
||||
Adres: { AdresPol: { Miasto: { _text: 'Warsaw' } } },
|
||||
AdresKoresp: { AdresPol: { Miasto: { _text: 'Gdansk' } } },
|
||||
},
|
||||
podmiot2KDto: {
|
||||
DaneIdentyfikacyjne: { NrID: { _text: 'IDK' } },
|
||||
Adres: { AdresZagr: { Kraj: { _text: 'PL' } } },
|
||||
},
|
||||
};
|
||||
const result = generateDaneIdentyfikacyjneTPodmiot3Dto(podmiot2KDto, 1);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ text: 'HEADER:Podmiot inny 2' },
|
||||
{ text: 'SUBHEADER:Dane identyfikacyjne' },
|
||||
{ text: 'LABEL:Numer EORI: EXX' },
|
||||
{ text: 'LABEL:Rola: SPRZEDAWCA' },
|
||||
{ text: 'LABEL:Rola inna: rola inna' },
|
||||
{ text: 'LABEL:Udział: 51%' },
|
||||
{ contact: 'KONTAKT' },
|
||||
{ text: 'LABEL:Numer klienta: KLIENTX' },
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('renders Adres korespondencyjny last in right column', () => {
|
||||
const podmiot2KDto: Podmiot3Podmiot2KDto = {
|
||||
fakturaPodmiotNDto: {
|
||||
AdresKoresp: { AdresPol: { Miasto: { _text: 'Gdynia' } } },
|
||||
},
|
||||
podmiot2KDto: {},
|
||||
};
|
||||
const result: Content[] = generateDaneIdentyfikacyjneTPodmiot3Dto(podmiot2KDto, 2);
|
||||
const twoCol: any = result.find((r: any): boolean => r.type === '2COL');
|
||||
|
||||
expect(twoCol.right[twoCol.right.length - 1]).toEqual({ adr: 'Adres korespondencyjny' });
|
||||
});
|
||||
});
|
||||
87
src/lib-public/generators/FA1/Podmiot3Podmiot2k.ts
Normal file
87
src/lib-public/generators/FA1/Podmiot3Podmiot2k.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
createSubHeader,
|
||||
generateTwoColumns,
|
||||
getTable,
|
||||
getValue,
|
||||
hasValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { Podmiot3Podmiot2KDto } from '../../types/fa1-additional-types';
|
||||
import { getRolaString } from '../../../shared/generators/common/functions';
|
||||
import { generatePodmiotAdres } from './PodmiotAdres';
|
||||
import { generateDaneIdentyfikacyjne } from './PodmiotDaneIdentyfikacyjne';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
import { Podmiot2K, Podmiot3 } from '../../types/fa1.types';
|
||||
|
||||
export function generateDaneIdentyfikacyjneTPodmiot3Dto(
|
||||
podmiot2KDto: Podmiot3Podmiot2KDto | undefined,
|
||||
index: number
|
||||
): Content[] {
|
||||
if (!podmiot2KDto) {
|
||||
return [];
|
||||
}
|
||||
const podmiot1: Podmiot3 = podmiot2KDto.fakturaPodmiotNDto;
|
||||
const podmiot1K: Podmiot2K | undefined = podmiot2KDto.podmiot2KDto;
|
||||
const result: Content[] = createHeader(`Podmiot inny ${index + 1}`);
|
||||
|
||||
if (
|
||||
hasValue(podmiot1.NrEORI) ||
|
||||
hasValue(podmiot1.Rola) ||
|
||||
hasValue(podmiot1.OpisRoli) ||
|
||||
hasValue(podmiot1?.Udzial)
|
||||
) {
|
||||
result.push(
|
||||
...createSubHeader('Dane identyfikacyjne'),
|
||||
createLabelText('Numer EORI: ', podmiot1.NrEORI),
|
||||
createLabelText('Rola: ', getRolaString(podmiot1.Rola, 1)),
|
||||
createLabelText('Rola inna: ', podmiot1.OpisRoli),
|
||||
createLabelText('Udział: ', podmiot1.Udzial, FormatTyp.Currency6)
|
||||
);
|
||||
}
|
||||
|
||||
if (podmiot1.Email || podmiot1.Telefon) {
|
||||
result.push(generateDaneKontaktowe(podmiot1.Email, getTable(podmiot1.Telefon)));
|
||||
}
|
||||
if (hasValue(podmiot1.NrKlienta)) {
|
||||
result.push(createLabelText('Numer klienta: ', podmiot1.NrKlienta));
|
||||
}
|
||||
const columns1: Content[] = [...createSubHeader('Treść korygowana')];
|
||||
|
||||
if (hasValue(podmiot1K?.DaneIdentyfikacyjne?.NrID)) {
|
||||
columns1.push(createLabelText('Identyfikator podatkowy inny: ', podmiot1K?.DaneIdentyfikacyjne?.NrID));
|
||||
}
|
||||
if (getValue(podmiot1K?.DaneIdentyfikacyjne?.BrakID) === '1') {
|
||||
columns1.push(createLabelText('Brak identyfikatora ', ' '));
|
||||
}
|
||||
|
||||
if (podmiot1K?.DaneIdentyfikacyjne) {
|
||||
columns1.push(generateDaneIdentyfikacyjne(podmiot1K.DaneIdentyfikacyjne));
|
||||
}
|
||||
if (podmiot1K?.Adres) {
|
||||
columns1.push(generatePodmiotAdres(podmiot1K.Adres, 'Adres', true));
|
||||
}
|
||||
const columns2: Content[] = [...createSubHeader('Treść korygująca')];
|
||||
|
||||
if (hasValue(podmiot1.DaneIdentyfikacyjne?.NrID)) {
|
||||
columns2.push(createLabelText('Identyfikator podatkowy inny: ', podmiot1.DaneIdentyfikacyjne?.NrID));
|
||||
}
|
||||
if (getValue(podmiot1.DaneIdentyfikacyjne?.BrakID) === '1') {
|
||||
columns2.push(createLabelText('Brak identyfikatora ', ' '));
|
||||
}
|
||||
|
||||
if (podmiot1?.DaneIdentyfikacyjne) {
|
||||
columns2.push(generateDaneIdentyfikacyjne(podmiot1.DaneIdentyfikacyjne));
|
||||
}
|
||||
if (podmiot1?.Adres) {
|
||||
columns2.push(generatePodmiotAdres(podmiot1.Adres, 'Adres', true));
|
||||
}
|
||||
|
||||
if (podmiot1.AdresKoresp != null) {
|
||||
columns2.push(generatePodmiotAdres(podmiot1.AdresKoresp, 'Adres korespondencyjny', true));
|
||||
}
|
||||
result.push(generateTwoColumns(columns1, columns2));
|
||||
return result;
|
||||
}
|
||||
48
src/lib-public/generators/FA1/PodmiotAdres.spec.ts
Normal file
48
src/lib-public/generators/FA1/PodmiotAdres.spec.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { generatePodmiotAdres } from './PodmiotAdres';
|
||||
import { Adres } from '../../types/fa1.types';
|
||||
import { Margins } from 'pdfmake/interfaces';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((title, margin) => [{ text: `HEADER:${title}`, margin }]),
|
||||
createSubHeader: vi.fn((title, margin) => [{ text: `SUBHEADER:${title}`, margin }]),
|
||||
}));
|
||||
vi.mock('./Adres', () => ({
|
||||
generateAdres: vi.fn((adres) => [{ text: `ADRES:${adres?.AdresPol?.Miasto?._text ?? ''}` }]),
|
||||
}));
|
||||
|
||||
describe('generatePodmiotAdres', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns empty array for undefined address', () => {
|
||||
expect(generatePodmiotAdres(undefined)).toEqual([]);
|
||||
});
|
||||
|
||||
it('renders with HEADER when isSubheader is false (default)', () => {
|
||||
const adres: Adres = { AdresPol: { Miasto: { _text: 'Katowice' } } };
|
||||
const result = generatePodmiotAdres(adres, 'Adres główny');
|
||||
|
||||
expect(result[0]).toEqual({ text: 'HEADER:Adres główny', margin: undefined });
|
||||
expect(result[1]).toEqual({ text: 'ADRES:Katowice' });
|
||||
});
|
||||
|
||||
it('renders with SUBHEADER and propagates headerMargin', () => {
|
||||
const adres: Adres = { AdresPol: { Miasto: { _text: 'Wrocław' } } };
|
||||
const margin: Margins = [2, 4, 6, 8];
|
||||
const result = generatePodmiotAdres(adres, 'Nagłówek podrzędny', true, margin);
|
||||
|
||||
expect(result[0]).toEqual({ text: 'SUBHEADER:Nagłówek podrzędny', margin });
|
||||
expect(result[1]).toEqual({ text: 'ADRES:Wrocław' });
|
||||
});
|
||||
|
||||
it('returns both header/subheader content and address output', () => {
|
||||
const adres: Adres = { AdresPol: { Miasto: { _text: 'Warszawa' } } };
|
||||
const resultHeader = generatePodmiotAdres(adres, 'Adres', false);
|
||||
const resultSub = generatePodmiotAdres(adres, 'Adres', true);
|
||||
|
||||
expect(resultHeader[0]).toEqual({ text: 'HEADER:Adres', margin: undefined });
|
||||
expect(resultSub[0]).toEqual({ text: 'SUBHEADER:Adres', margin: undefined });
|
||||
expect(resultHeader[1]).toEqual({ text: 'ADRES:Warszawa' });
|
||||
expect(resultSub[1]).toEqual({ text: 'ADRES:Warszawa' });
|
||||
});
|
||||
});
|
||||
19
src/lib-public/generators/FA1/PodmiotAdres.ts
Normal file
19
src/lib-public/generators/FA1/PodmiotAdres.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Content, Margins } from 'pdfmake/interfaces';
|
||||
import { createHeader, createSubHeader } from '../../../shared/PDF-functions';
|
||||
import { Adres } from '../../types/fa1.types';
|
||||
import { generateAdres } from './Adres';
|
||||
|
||||
export function generatePodmiotAdres(
|
||||
podmiotAdres: Adres | undefined,
|
||||
headerTitle = 'Adres',
|
||||
isSubheader = false,
|
||||
headerMargin?: Margins
|
||||
): Content[] {
|
||||
if (!podmiotAdres) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
...(isSubheader ? createSubHeader(headerTitle, headerMargin) : createHeader(headerTitle, headerMargin)),
|
||||
...generateAdres(podmiotAdres),
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generateDaneIdentyfikacyjne } from './PodmiotDaneIdentyfikacyjne';
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { DaneIdentyfikacyjneTPodmiot2Dto } from '../../types/fa2-additional-types';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createLabelText: vi.fn((label, value) => ({
|
||||
text: `LABEL:${label}${typeof value === 'object' && value?._text ? value._text : (value ?? '')}`,
|
||||
})),
|
||||
getValue: vi.fn((val) => (val && val._text ? val._text : '')),
|
||||
hasValue: vi.fn((val) => !!(val && val._text)),
|
||||
}));
|
||||
|
||||
describe('generateDaneIdentyfikacyjne', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('adds NIP label always', () => {
|
||||
const dane: DaneIdentyfikacyjneTPodmiot2Dto = { NIP: { _text: '1111111111' } };
|
||||
const result = generateDaneIdentyfikacyjne(dane);
|
||||
|
||||
expect(result[0]).toEqual({ text: 'LABEL:NIP: 1111111111' });
|
||||
});
|
||||
|
||||
it('skips name/last name label for empty values', () => {
|
||||
const dane: DaneIdentyfikacyjneTPodmiot2Dto = { NIP: { _text: 'xx' } };
|
||||
const result: Content[] = generateDaneIdentyfikacyjne(dane);
|
||||
|
||||
expect(result.some((r: any): boolean => r.text === 'LABEL: ')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('adds Pełna nazwa label when present', () => {
|
||||
const dane: DaneIdentyfikacyjneTPodmiot2Dto = {
|
||||
NIP: { _text: '99' },
|
||||
PelnaNazwa: { _text: 'INSTRUMENTS INC.' },
|
||||
};
|
||||
const result = generateDaneIdentyfikacyjne(dane);
|
||||
|
||||
expect(result).toEqual(expect.arrayContaining([{ text: 'LABEL:Pełna nazwa: INSTRUMENTS INC.' }]));
|
||||
});
|
||||
|
||||
it('adds Nazwa handlowa when surname is present', () => {
|
||||
const dane: DaneIdentyfikacyjneTPodmiot2Dto = {
|
||||
NIP: { _text: '43210' },
|
||||
Nazwisko: { _text: 'Smith' },
|
||||
NazwaHandlowa: { _text: 'Smithy PLC' },
|
||||
};
|
||||
const result = generateDaneIdentyfikacyjne(dane);
|
||||
|
||||
expect(result).toEqual(expect.arrayContaining([{ text: 'LABEL:Nazwa handlowa: Smithy PLC' }]));
|
||||
});
|
||||
|
||||
it('returns array including only expected fields', () => {
|
||||
const dane: DaneIdentyfikacyjneTPodmiot2Dto = {
|
||||
NIP: { _text: '11' },
|
||||
PelnaNazwa: { _text: 'Best Corp' },
|
||||
};
|
||||
const result = generateDaneIdentyfikacyjne(dane);
|
||||
|
||||
expect(result.length).toBe(2);
|
||||
expect(result).toEqual([{ text: 'LABEL:NIP: 11' }, { text: 'LABEL:Pełna nazwa: Best Corp' }]);
|
||||
});
|
||||
});
|
||||
24
src/lib-public/generators/FA1/PodmiotDaneIdentyfikacyjne.ts
Normal file
24
src/lib-public/generators/FA1/PodmiotDaneIdentyfikacyjne.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { createLabelText, getValue, hasValue } from '../../../shared/PDF-functions';
|
||||
import { DaneIdentyfikacyjneTPodmiot2Dto } from '../../types/fa2-additional-types';
|
||||
|
||||
export function generateDaneIdentyfikacyjne(daneIdentyfikacyjne: DaneIdentyfikacyjneTPodmiot2Dto): Content[] {
|
||||
const result: Content[] = [];
|
||||
|
||||
result.push(createLabelText('NIP: ', daneIdentyfikacyjne.NIP));
|
||||
if (hasValue(daneIdentyfikacyjne.ImiePierwsze) || hasValue(daneIdentyfikacyjne.Nazwisko)) {
|
||||
result.push(
|
||||
createLabelText(
|
||||
'',
|
||||
`${getValue(daneIdentyfikacyjne.ImiePierwsze)} ${getValue(daneIdentyfikacyjne.Nazwisko)}`
|
||||
)
|
||||
);
|
||||
}
|
||||
if (daneIdentyfikacyjne.PelnaNazwa) {
|
||||
result.push(createLabelText('Pełna nazwa: ', daneIdentyfikacyjne.PelnaNazwa));
|
||||
}
|
||||
if (daneIdentyfikacyjne.Nazwisko) {
|
||||
result.push(createLabelText('Nazwa handlowa: ', daneIdentyfikacyjne.NazwaHandlowa));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
49
src/lib-public/generators/FA1/PodmiotDaneKontaktowe.spec.ts
Normal file
49
src/lib-public/generators/FA1/PodmiotDaneKontaktowe.spec.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
import { FP } from '../../types/fa1.types';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createLabelText: vi.fn((label: string, value: any) => ({
|
||||
text: `LABEL:${label}${typeof value === 'object' && value?._text ? value._text : (value ?? '')}`,
|
||||
})),
|
||||
}));
|
||||
|
||||
describe('generateDaneKontaktowe', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns empty array for no input', () => {
|
||||
expect(generateDaneKontaktowe()).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns only email entry when only email is present', () => {
|
||||
const email: FP = { _text: 'aa@bb.cc' };
|
||||
const result = generateDaneKontaktowe(email, undefined);
|
||||
|
||||
expect(result).toEqual([{ text: 'LABEL:Email: aa@bb.cc' }]);
|
||||
});
|
||||
|
||||
it('returns only tel entry when only single phone is present', () => {
|
||||
const tel = [{ _text: '123456789' }];
|
||||
const result = generateDaneKontaktowe(undefined, tel);
|
||||
|
||||
expect(result).toEqual([{ text: 'LABEL:Tel.: [object Object]\n' }]);
|
||||
});
|
||||
|
||||
it('returns email and all telephones in order', () => {
|
||||
const email: FP = { _text: 'z@x.io' };
|
||||
const telo = [{ _text: '101' }, { _text: '202' }];
|
||||
const result = generateDaneKontaktowe(email, telo);
|
||||
|
||||
expect(result[0]).toEqual({ text: 'LABEL:Email: z@x.io' });
|
||||
expect(result.length).toBe(3);
|
||||
expect(result[1]).toEqual({ text: 'LABEL:Tel.: [object Object]\n' });
|
||||
expect(result[2]).toEqual({ text: 'LABEL:Tel.: [object Object]\n' });
|
||||
});
|
||||
|
||||
it('handles multiple telephones', () => {
|
||||
const tel = [{ _text: '666111222' }, { _text: '555222111' }];
|
||||
const result = generateDaneKontaktowe(undefined, tel);
|
||||
|
||||
expect(result.length).toBe(2);
|
||||
});
|
||||
});
|
||||
17
src/lib-public/generators/FA1/PodmiotDaneKontaktowe.ts
Normal file
17
src/lib-public/generators/FA1/PodmiotDaneKontaktowe.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { createLabelText } from '../../../shared/PDF-functions';
|
||||
import { FP } from '../../types/fa1.types';
|
||||
|
||||
export function generateDaneKontaktowe(email?: FP, telefon?: FP[]): Content[] {
|
||||
const result: Content[] = [];
|
||||
|
||||
if (email) {
|
||||
result.push(createLabelText('Email: ', email));
|
||||
}
|
||||
if (telefon) {
|
||||
telefon.forEach((item) => {
|
||||
result.push(createLabelText('Tel.: ', `${item}\n`));
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
46
src/lib-public/generators/FA1/PodmiotUpowazniony.spec.ts
Normal file
46
src/lib-public/generators/FA1/PodmiotUpowazniony.spec.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((label) => [{ text: `HEADER:${label}` }]),
|
||||
createLabelText: vi.fn((label, value) => ({
|
||||
text: `LABEL:${label}${value && value._text ? value._text : (value ?? '')}`,
|
||||
})),
|
||||
formatText: vi.fn((txt, _args) => ({ text: `FMT:${txt}` })),
|
||||
getTable: vi.fn((arr) => arr || []),
|
||||
getValue: vi.fn((val) => (val && val._text ? val._text : '')),
|
||||
hasValue: vi.fn((val) => Boolean(val && val._text)),
|
||||
generateTwoColumns: vi.fn((left, right) => ({ type: '2COL', left, right })),
|
||||
}));
|
||||
|
||||
vi.mock('../../../shared/generators/common/functions', () => ({
|
||||
getRolaUpowaznionegoString: vi.fn(() => 'Rola string'),
|
||||
}));
|
||||
vi.mock('./PodmiotAdres', () => ({
|
||||
generatePodmiotAdres: vi.fn((adres, label) => ({ adr: label })),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjne', () => ({
|
||||
generateDaneIdentyfikacyjne: vi.fn(() => [{ id: 'ID' }]),
|
||||
}));
|
||||
vi.mock('./PodmiotDaneKontaktowe', () => ({
|
||||
generateDaneKontaktowe: vi.fn(() => ({ contact: 'KONTAKT' })),
|
||||
}));
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generatePodmiotUpowazniony } from './PodmiotUpowazniony';
|
||||
import { PodmiotUpowazniony } from '../../types/fa1.types';
|
||||
|
||||
describe(generatePodmiotUpowazniony.name, () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns empty if input undefined', () => {
|
||||
expect(generatePodmiotUpowazniony(undefined)).toEqual([]);
|
||||
});
|
||||
|
||||
it('renders header and basic role and EORI if present', () => {
|
||||
const podmiot: PodmiotUpowazniony = {
|
||||
RolaPU: { _text: 'X' },
|
||||
NrEORI: { _text: 'EORI123' },
|
||||
};
|
||||
const res = generatePodmiotUpowazniony(podmiot);
|
||||
expect(res[0]).toEqual({ text: 'HEADER:Podmiot upoważniony' });
|
||||
expect(res.some((r: any) => r.type === '2COL')).toBe(true);
|
||||
});
|
||||
});
|
||||
56
src/lib-public/generators/FA1/PodmiotUpowazniony.ts
Normal file
56
src/lib-public/generators/FA1/PodmiotUpowazniony.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
formatText,
|
||||
generateTwoColumns,
|
||||
getTable,
|
||||
getValue,
|
||||
hasValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { PodmiotUpowazniony } from '../../types/fa1.types';
|
||||
import { generatePodmiotAdres } from './PodmiotAdres';
|
||||
import { generateDaneIdentyfikacyjne } from './PodmiotDaneIdentyfikacyjne';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
import { getRolaUpowaznionegoString } from '../../../shared/generators/common/functions';
|
||||
|
||||
export function generatePodmiotUpowazniony(podmiot: PodmiotUpowazniony | undefined): Content[] {
|
||||
if (!podmiot) {
|
||||
return [];
|
||||
}
|
||||
const result: Content[] = createHeader('Podmiot upoważniony');
|
||||
const columnLeft: Content[] = [];
|
||||
const columnRight: Content[] = [];
|
||||
|
||||
if (hasValue(podmiot.RolaPU)) {
|
||||
columnLeft.push(createLabelText('Rola: ', getRolaUpowaznionegoString(podmiot.RolaPU, 1)));
|
||||
}
|
||||
if (hasValue(podmiot.NrEORI)) {
|
||||
columnLeft.push(createLabelText('NrEORI: ', podmiot.NrEORI));
|
||||
}
|
||||
if (podmiot.DaneIdentyfikacyjne) {
|
||||
if (hasValue(podmiot.DaneIdentyfikacyjne.NrID)) {
|
||||
columnLeft.push(createLabelText('Identyfikator podatkowy inny: ', podmiot.DaneIdentyfikacyjne.NrID));
|
||||
}
|
||||
if (getValue(podmiot.DaneIdentyfikacyjne.BrakID) === '1') {
|
||||
columnLeft.push(createLabelText('Brak identyfikatora ', ' '));
|
||||
}
|
||||
columnLeft.push(generateDaneIdentyfikacyjne(podmiot.DaneIdentyfikacyjne));
|
||||
}
|
||||
|
||||
if (podmiot.Adres) {
|
||||
columnRight.push(generatePodmiotAdres(podmiot.Adres, 'Adres', true));
|
||||
}
|
||||
if (podmiot.AdresKoresp) {
|
||||
columnRight.push(generatePodmiotAdres(podmiot.AdresKoresp, 'Adres do korespondencji', true));
|
||||
}
|
||||
if (podmiot.EmailPU || podmiot.TelefonPU) {
|
||||
columnRight.push(
|
||||
formatText('Dane kontaktowe', [FormatTyp.Label]),
|
||||
...generateDaneKontaktowe(podmiot.EmailPU, getTable(podmiot.TelefonPU))
|
||||
);
|
||||
}
|
||||
result.push(generateTwoColumns(columnLeft, columnRight));
|
||||
return result;
|
||||
}
|
||||
118
src/lib-public/generators/FA1/Podmioty.spec.ts
Normal file
118
src/lib-public/generators/FA1/Podmioty.spec.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generatePodmioty } from './Podmioty';
|
||||
import { Faktura } from '../../types/fa1.types';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createSection: vi.fn((arr) => arr),
|
||||
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)),
|
||||
}));
|
||||
vi.mock('./Podmiot1', () => ({
|
||||
generatePodmiot1: vi.fn(() => [{ podmiot1: true }]),
|
||||
}));
|
||||
vi.mock('./Podmiot1Podmiot1K', () => ({
|
||||
generatePodmiot1Podmiot1K: vi.fn(() => [{ podmiot1K: true }]),
|
||||
}));
|
||||
vi.mock('./Podmiot2', () => ({
|
||||
generatePodmiot2: vi.fn(() => [{ podmiot2: true }]),
|
||||
}));
|
||||
vi.mock('./Podmiot2Podmiot2k', () => ({
|
||||
generatePodmiot2Podmiot2K: vi.fn(() => [{ podmiot2K: true }]),
|
||||
}));
|
||||
vi.mock('./Podmiot3', () => ({
|
||||
generatePodmiot3: vi.fn(() => [{ podmiot3: true }]),
|
||||
}));
|
||||
vi.mock('./Podmiot3Podmiot2k', () => ({
|
||||
generateDaneIdentyfikacyjneTPodmiot3Dto: vi.fn(() => [{ daneIdentyfikacyjne: true }]),
|
||||
}));
|
||||
vi.mock('./PodmiotUpowazniony', () => ({
|
||||
generatePodmiotUpowazniony: vi.fn(() => [{ upowazniony: true }]),
|
||||
}));
|
||||
vi.mock('../../../shared/generators/common/functions', () => ({
|
||||
getValue: vi.fn((val) => (val && val._text ? val._text : '')),
|
||||
}));
|
||||
|
||||
describe(generatePodmioty.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('calls generatePodmiot1Podmiot1K when Podmiot1K exists', () => {
|
||||
const invoice: Faktura = {
|
||||
Podmiot1: {},
|
||||
Podmiot2: {},
|
||||
Fa: {
|
||||
Podmiot1K: {},
|
||||
Podmiot2K: [{}],
|
||||
},
|
||||
};
|
||||
const result = generatePodmioty(invoice);
|
||||
|
||||
expect(result).toContainEqual(expect.arrayContaining([{ podmiot1K: true }]));
|
||||
});
|
||||
|
||||
it('calls generatePodmiot1 when Podmiot1K missing', () => {
|
||||
const invoice: Faktura = {
|
||||
Podmiot1: {},
|
||||
Podmiot2: {},
|
||||
Fa: {
|
||||
Podmiot2K: [{}],
|
||||
},
|
||||
};
|
||||
const result = generatePodmioty(invoice);
|
||||
|
||||
expect(result).toContainEqual(expect.arrayContaining([{ podmiot1: true }]));
|
||||
});
|
||||
|
||||
it('calls generatePodmiot2Podmiot2K when Podmiot2K available', () => {
|
||||
const invoice: Faktura = {
|
||||
Podmiot2: {},
|
||||
Fa: {
|
||||
Podmiot2K: [{}, {}],
|
||||
},
|
||||
};
|
||||
const result = generatePodmioty(invoice);
|
||||
|
||||
expect(result).toContainEqual(expect.arrayContaining([{ podmiot2K: true }]));
|
||||
});
|
||||
|
||||
it('renders Podmiot1 and Podmiot2 side by side if no Fa Podmiot1K or Podmiot2K', () => {
|
||||
const invoice: Faktura = {
|
||||
Podmiot1: {},
|
||||
Podmiot2: {},
|
||||
};
|
||||
const result = generatePodmioty(invoice);
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
columns: expect.any(Array),
|
||||
}),
|
||||
]),
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('calls generateDaneIdentyfikacyjneTPodmiot3Dto or generatePodmiot3 accordingly', () => {
|
||||
const invoice: Faktura = {
|
||||
Podmiot3: [{ Rola: { _text: '4' } }],
|
||||
Fa: {
|
||||
Podmiot2K: [{}, {}],
|
||||
},
|
||||
};
|
||||
const result = generatePodmioty(invoice);
|
||||
|
||||
expect(result.some((e: any) => e.some((o: any) => o.daneIdentyfikacyjne || o.podmiot3))).toBe(true);
|
||||
});
|
||||
|
||||
it('calls generatePodmiotUpowazniony last', () => {
|
||||
const invoice: Faktura = {
|
||||
PodmiotUpowazniony: {},
|
||||
};
|
||||
const result = generatePodmioty(invoice);
|
||||
|
||||
expect(result).toContainEqual(expect.arrayContaining([{ upowazniony: true }]));
|
||||
});
|
||||
});
|
||||
95
src/lib-public/generators/FA1/Podmioty.ts
Normal file
95
src/lib-public/generators/FA1/Podmioty.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { createSection, 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';
|
||||
import { generatePodmiot1Podmiot1K } from './Podmiot1Podmiot1K';
|
||||
import { generatePodmiot2 } from './Podmiot2';
|
||||
import { generatePodmiot2Podmiot2K } from './Podmiot2Podmiot2k';
|
||||
import { generatePodmiot3 } from './Podmiot3';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot3Dto } from './Podmiot3Podmiot2k';
|
||||
import { generatePodmiotUpowazniony } from './PodmiotUpowazniony';
|
||||
|
||||
export function generatePodmioty(invoice: Faktura): Content[] {
|
||||
const result: Content[] = [];
|
||||
const podmiot2K: Podmiot2K[] = getTable(invoice.Fa?.Podmiot2K);
|
||||
const podmiot3: Podmiot3[] = getTable(invoice.Podmiot3);
|
||||
|
||||
if (invoice.Fa?.Podmiot1K || podmiot2K.length > 0) {
|
||||
if (invoice.Fa?.Podmiot1K) {
|
||||
result.push(generatePodmiot1Podmiot1K(invoice.Podmiot1 ?? {}, invoice.Fa?.Podmiot1K));
|
||||
} else if (invoice.Podmiot1 != null) {
|
||||
result.push(generatePodmiot1(invoice.Podmiot1));
|
||||
}
|
||||
|
||||
if (podmiot2K.length > 0) {
|
||||
podmiot2K.forEach((podmiot2K: Podmiot2K): void => {
|
||||
result.push(generatePodmiot2Podmiot2K(invoice.Podmiot2 ?? {}, podmiot2K));
|
||||
});
|
||||
} else if (invoice.Podmiot2) {
|
||||
result.push(createSection(generatePodmiot2(invoice.Podmiot2!), true));
|
||||
}
|
||||
} else {
|
||||
result.push([
|
||||
{
|
||||
columns: [generatePodmiot1(invoice.Podmiot1!), generatePodmiot2(invoice.Podmiot2!)],
|
||||
margin: [0, 0, 0, 8],
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
if (podmiot3.length > 0) {
|
||||
const podmiot3Podmiot2KDto: Podmiot3Podmiot2KDto[] = getPodmiot3Podmiot2KDto(podmiot2K, podmiot3);
|
||||
|
||||
if (podmiot3Podmiot2KDto.length > 0) {
|
||||
podmiot3Podmiot2KDto.forEach((pdm2KDto: Podmiot3Podmiot2KDto, i: number): void => {
|
||||
if (pdm2KDto.podmiot2KDto) {
|
||||
result.push(generateDaneIdentyfikacyjneTPodmiot3Dto(pdm2KDto, i));
|
||||
} else {
|
||||
result.push(generatePodmiot3(pdm2KDto.fakturaPodmiotNDto, i));
|
||||
}
|
||||
if (i < podmiot3Podmiot2KDto.length - 1) {
|
||||
result.push({ margin: [0, 8, 0, 0], text: '' });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
podmiot3.forEach((podmiot: Podmiot3, index: number): void => {
|
||||
result.push(generatePodmiot3(podmiot, index));
|
||||
if (index < podmiot3.length - 1) {
|
||||
result.push({ margin: [0, 8, 0, 0], text: '' });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
result.push(generatePodmiotUpowazniony(invoice.PodmiotUpowazniony));
|
||||
return createSection(result, true);
|
||||
}
|
||||
|
||||
function getPodmiot3Podmiot2KDto(podmioty2K: Podmiot2K[], podmioty3: Podmiot3[]): Podmiot3Podmiot2KDto[] {
|
||||
const result: Podmiot3Podmiot2KDto[] = [];
|
||||
|
||||
if (
|
||||
podmioty2K.length > 1 &&
|
||||
podmioty3.filter((p: Podmiot3): boolean => getValue(p.Rola) === '4').length > 0
|
||||
) {
|
||||
let idx: number = 1;
|
||||
|
||||
podmioty3.forEach((podmiot3) => {
|
||||
if (getValue(podmiot3.Rola) === '4') {
|
||||
if (podmioty2K.length > idx) {
|
||||
result.push({
|
||||
fakturaPodmiotNDto: podmiot3,
|
||||
podmiot2KDto: podmioty2K[idx],
|
||||
});
|
||||
}
|
||||
idx++;
|
||||
} else {
|
||||
result.push({
|
||||
fakturaPodmiotNDto: podmiot3,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { Fa, Faktura, FP } from '../../types/fa1.types';
|
||||
import { generatePodsumowanieStawekPodatkuVat, getSummaryTaxRate } from './PodsumowanieStawekPodatkuVat';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((label) => [{ text: `HEADER:${label}` }]),
|
||||
createSection: vi.fn((input) => input),
|
||||
formatText: vi.fn((text, style) => ({ text, style })),
|
||||
getValue: vi.fn((val) =>
|
||||
val && val._text ? (typeof val._text === 'string' ? val._text : val._text.toString()) : ''
|
||||
),
|
||||
hasValue: vi.fn((val) => !!(val && val._text)),
|
||||
getNumberRounded: vi.fn((val) => (typeof val === 'number' ? val : parseFloat(val?._text ?? '0') || 0)),
|
||||
}));
|
||||
|
||||
describe('generatePodsumowanieStawekPodatkuVat', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns empty array if no relevant Fa data', () => {
|
||||
const faktura: Faktura = { Fa: {} as Fa };
|
||||
|
||||
expect(generatePodsumowanieStawekPodatkuVat(faktura)).toEqual([]);
|
||||
});
|
||||
|
||||
it('creates table with header and data rows', () => {
|
||||
const fa: Fa = {
|
||||
P_13_1: { _text: '100' },
|
||||
P_14_1: { _text: '23' },
|
||||
P_14_1W: { _text: '23' },
|
||||
};
|
||||
const faktura: Faktura = { Fa: fa };
|
||||
|
||||
const result: any = generatePodsumowanieStawekPodatkuVat(faktura);
|
||||
|
||||
expect(result.some((r: any) => r.table && r.table.body)).toBeTruthy();
|
||||
expect(result[0].text).toContain('Podsumowanie stawek podatku'); // header present
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSummaryTaxRate', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns empty summarization if no values', () => {
|
||||
const fa: Fa = {};
|
||||
|
||||
expect(getSummaryTaxRate(fa)).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns correct summary entries for each tax rate', () => {
|
||||
const floatText = (num: number): FP => ({ _text: num.toString() });
|
||||
|
||||
const fa: Fa = {
|
||||
P_13_1: floatText(100),
|
||||
P_14_1: floatText(23),
|
||||
P_14_1W: floatText(23),
|
||||
P_13_2: floatText(200),
|
||||
P_14_2: floatText(16),
|
||||
P_14_2W: floatText(16),
|
||||
P_13_3: floatText(300),
|
||||
P_14_3: floatText(15),
|
||||
P_14_3W: floatText(15),
|
||||
P_13_4: floatText(400),
|
||||
P_14_4: floatText(12),
|
||||
P_14_4W: floatText(12),
|
||||
P_13_5: floatText(500),
|
||||
P_14_5: floatText(0),
|
||||
P_13_7: floatText(600),
|
||||
};
|
||||
|
||||
const summary = getSummaryTaxRate(fa);
|
||||
|
||||
expect(summary.length).toBe(6);
|
||||
expect(summary[0]).toMatchObject({
|
||||
no: 1,
|
||||
taxRateString: '23% lub 22%',
|
||||
net: '100.00',
|
||||
tax: '23.00',
|
||||
taxPLN: '23.00',
|
||||
gross: '123.00',
|
||||
});
|
||||
expect(summary[1].taxRateString).toBe('8% lub 7%');
|
||||
expect(summary[4].taxRateString).toBe('');
|
||||
expect(summary[5].taxRateString).toBe('zwolnione z opodatkowania');
|
||||
});
|
||||
|
||||
it('includes only tax rates with non-zero values', () => {
|
||||
const fa: Fa = {
|
||||
P_13_1: { _text: '0' },
|
||||
P_14_1: { _text: '0' },
|
||||
P_14_1W: { _text: '0' },
|
||||
};
|
||||
|
||||
expect(getSummaryTaxRate(fa)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
189
src/lib-public/generators/FA1/PodsumowanieStawekPodatkuVat.ts
Normal file
189
src/lib-public/generators/FA1/PodsumowanieStawekPodatkuVat.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
import { Content, ContentTable, ContentText, TableCell } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createSection,
|
||||
formatText,
|
||||
getNumberRounded,
|
||||
getValue,
|
||||
hasValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { Fa, Faktura, FP } from '../../types/fa1.types';
|
||||
import { TaxSummaryTypes } from '../../types/tax-summary.types';
|
||||
import { DEFAULT_TABLE_LAYOUT } from '../../../shared/consts/const';
|
||||
|
||||
export function generatePodsumowanieStawekPodatkuVat(faktura: Faktura): Content[] {
|
||||
const AnyP13P14_5Diff0: boolean =
|
||||
hasValue(faktura.Fa?.P_13_1) ||
|
||||
hasValue(faktura.Fa?.P_13_2) ||
|
||||
hasValue(faktura.Fa?.P_13_3) ||
|
||||
hasValue(faktura.Fa?.P_13_4) ||
|
||||
(hasValue(faktura.Fa?.P_13_5) && (!hasValue(faktura.Fa?.P_14_5) || getValue(faktura.Fa?.P_14_5) == 0)) ||
|
||||
hasValue(faktura.Fa?.P_13_6) ||
|
||||
hasValue(faktura.Fa?.P_13_7);
|
||||
const AnyP13: boolean =
|
||||
hasValue(faktura.Fa?.P_13_1) ||
|
||||
hasValue(faktura.Fa?.P_13_2) ||
|
||||
hasValue(faktura.Fa?.P_13_3) ||
|
||||
hasValue(faktura.Fa?.P_13_4) ||
|
||||
hasValue(faktura.Fa?.P_13_5) ||
|
||||
hasValue(faktura.Fa?.P_13_7);
|
||||
const AnyP_14xW: boolean =
|
||||
hasValue(faktura.Fa?.P_14_1W) ||
|
||||
hasValue(faktura.Fa?.P_14_2W) ||
|
||||
hasValue(faktura.Fa?.P_14_3W) ||
|
||||
hasValue(faktura.Fa?.P_14_4W);
|
||||
|
||||
let tableBody: TableCell[] = [];
|
||||
const table: ContentTable = {
|
||||
table: {
|
||||
headerRows: 1,
|
||||
widths: [],
|
||||
body: [] as TableCell[][],
|
||||
},
|
||||
layout: DEFAULT_TABLE_LAYOUT,
|
||||
};
|
||||
|
||||
const definedHeader: Content[] = [
|
||||
...[{ text: 'Lp.', style: FormatTyp.GrayBoldTitle }],
|
||||
...(AnyP13P14_5Diff0 ? [{ text: 'Stawka podatku', style: FormatTyp.GrayBoldTitle }] : []),
|
||||
...(AnyP13 ? [{ text: 'Kwota netto', style: FormatTyp.GrayBoldTitle }] : []),
|
||||
...(AnyP13P14_5Diff0 ? [{ text: 'Kwota podatku', style: FormatTyp.GrayBoldTitle }] : []),
|
||||
...(AnyP13 ? [{ text: 'Kwota brutto', style: FormatTyp.GrayBoldTitle }] : []),
|
||||
...(AnyP_14xW ? [{ text: 'Kwota podatku PLN', style: FormatTyp.GrayBoldTitle }] : []),
|
||||
];
|
||||
|
||||
const widths: Content[] = [
|
||||
...['auto'],
|
||||
...(AnyP13P14_5Diff0 ? ['*'] : []),
|
||||
...(AnyP13 ? ['*'] : []),
|
||||
...(AnyP13P14_5Diff0 ? ['*'] : []),
|
||||
...(AnyP13 ? ['*'] : []),
|
||||
...(AnyP_14xW ? ['*'] : []),
|
||||
];
|
||||
|
||||
if (faktura?.Fa) {
|
||||
const summary: TaxSummaryTypes[] = getSummaryTaxRate(faktura.Fa);
|
||||
|
||||
tableBody = summary.map((item: TaxSummaryTypes): (string | number | ContentText)[] => {
|
||||
const data: (string | number | ContentText)[] = [];
|
||||
|
||||
data.push(item.no);
|
||||
if (AnyP13P14_5Diff0) {
|
||||
data.push(item.taxRateString);
|
||||
}
|
||||
if (AnyP13) {
|
||||
data.push(formatText(item.net, FormatTyp.Currency));
|
||||
}
|
||||
if (AnyP13P14_5Diff0) {
|
||||
data.push(formatText(item.tax, FormatTyp.Currency));
|
||||
}
|
||||
if (AnyP13) {
|
||||
data.push(formatText(item.gross, FormatTyp.Currency));
|
||||
}
|
||||
if (AnyP_14xW) {
|
||||
data.push(formatText(item.taxPLN, FormatTyp.Currency));
|
||||
}
|
||||
return data;
|
||||
});
|
||||
}
|
||||
table.table.body = [[...definedHeader], ...tableBody] as TableCell[][];
|
||||
table.table.widths = [...widths] as never[];
|
||||
|
||||
return tableBody.length
|
||||
? createSection([...createHeader('Podsumowanie stawek podatku', [0, 0, 0, 8]), table], false)
|
||||
: [];
|
||||
}
|
||||
|
||||
export function getSummaryTaxRate(fa: Fa): TaxSummaryTypes[] {
|
||||
const summary: TaxSummaryTypes[] = [];
|
||||
|
||||
const AnyP13_1P14_1P14_1WDiff0 =
|
||||
hasValueAndDiff0(fa?.P_13_1) || hasValueAndDiff0(fa?.P_14_1) || hasValueAndDiff0(fa?.P_14_1W);
|
||||
const AnyP13_2P14_2P14_2WDiff0 =
|
||||
hasValueAndDiff0(fa?.P_13_2) || hasValueAndDiff0(fa?.P_14_2) || hasValueAndDiff0(fa?.P_14_2W);
|
||||
const AnyP13_3P14_3P14_3WDiff0 =
|
||||
hasValueAndDiff0(fa?.P_13_3) || hasValueAndDiff0(fa?.P_14_3) || hasValueAndDiff0(fa?.P_14_3W);
|
||||
const AnyP13_4P14_4P14_4WDiff0 =
|
||||
hasValueAndDiff0(fa?.P_13_4) || hasValueAndDiff0(fa?.P_14_4) || hasValueAndDiff0(fa?.P_14_4W);
|
||||
const AnyP13_5P14_5Diff0 = hasValueAndDiff0(fa?.P_13_5) || hasValueAndDiff0(fa?.P_14_5);
|
||||
const AnyP13_7Diff0 = hasValueAndDiff0(fa?.P_13_7);
|
||||
let no = 1;
|
||||
|
||||
if (AnyP13_1P14_1P14_1WDiff0) {
|
||||
summary.push({
|
||||
no,
|
||||
net: getNumberRounded(fa.P_13_1).toFixed(2),
|
||||
gross: (getNumberRounded(fa.P_13_1) + getNumberRounded(fa.P_14_1)).toFixed(2),
|
||||
tax: getNumberRounded(fa.P_14_1).toFixed(2),
|
||||
taxPLN: getNumberRounded(fa.P_14_1W).toFixed(2),
|
||||
taxRateString: '23% lub 22%',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
|
||||
if (AnyP13_2P14_2P14_2WDiff0) {
|
||||
summary.push({
|
||||
no,
|
||||
net: getNumberRounded(fa.P_13_2).toFixed(2),
|
||||
gross: (getNumberRounded(fa.P_13_2) + getNumberRounded(fa.P_14_2)).toFixed(2),
|
||||
tax: getNumberRounded(fa.P_14_2).toFixed(2),
|
||||
taxPLN: getNumberRounded(fa.P_14_2W).toFixed(2),
|
||||
taxRateString: '8% lub 7%',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
|
||||
if (AnyP13_3P14_3P14_3WDiff0) {
|
||||
summary.push({
|
||||
no,
|
||||
net: getNumberRounded(fa.P_13_3).toFixed(2),
|
||||
gross: (getNumberRounded(fa.P_13_3) + getNumberRounded(fa.P_14_3)).toFixed(2),
|
||||
tax: getNumberRounded(fa.P_14_3).toFixed(2),
|
||||
taxPLN: getNumberRounded(fa.P_14_3W).toFixed(2),
|
||||
taxRateString: '5%',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
|
||||
if (AnyP13_4P14_4P14_4WDiff0) {
|
||||
summary.push({
|
||||
no,
|
||||
net: getNumberRounded(fa.P_13_4).toFixed(2),
|
||||
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',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
|
||||
if (AnyP13_5P14_5Diff0) {
|
||||
summary.push({
|
||||
no,
|
||||
net: getNumberRounded(fa.P_13_5).toFixed(2),
|
||||
gross: getNumberRounded(fa.P_13_5).toFixed(2),
|
||||
tax: getNumberRounded(fa.P_14_5).toFixed(2),
|
||||
taxPLN: '',
|
||||
taxRateString: getValue(fa.P_14_5) != 0 ? 'niepodlegające opodatkowaniu' : '',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
|
||||
if (AnyP13_7Diff0) {
|
||||
summary.push({
|
||||
no,
|
||||
net: getNumberRounded(fa.P_13_7).toFixed(2),
|
||||
gross: getNumberRounded(fa.P_13_7).toFixed(2),
|
||||
tax: '0.00',
|
||||
taxPLN: '',
|
||||
taxRateString: 'zwolnione z opodatkowania',
|
||||
});
|
||||
no++;
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
||||
function hasValueAndDiff0(value: FP | string | number | undefined): boolean {
|
||||
return hasValue(value) && getValue(value) != 0;
|
||||
}
|
||||
34
src/lib-public/generators/FA1/Przewoznik.spec.ts
Normal file
34
src/lib-public/generators/FA1/Przewoznik.spec.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generatePrzewoznik } from './Przewoznik';
|
||||
import { Przewoznik } from '../../types/fa1.types';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((label) => [{ text: `HEADER:${label}` }]),
|
||||
generateTwoColumns: vi.fn((left, right, margin) => ({ left, right, margin, type: '2COL' })),
|
||||
}));
|
||||
|
||||
vi.mock('./PodmiotAdres', () => ({
|
||||
generatePodmiotAdres: vi.fn(() => ({ adr: 'AdresPrzewoznika' })),
|
||||
}));
|
||||
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjne', () => ({
|
||||
generateDaneIdentyfikacyjne: vi.fn(() => [{ id: 'DaneIdentyfikacyjne' }]),
|
||||
}));
|
||||
|
||||
describe('generatePrzewoznik', () => {
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
it('returns empty array if przewoznik is undefined', () => {
|
||||
expect(generatePrzewoznik(undefined)).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns header and twoColumns for valid przewoznik', () => {
|
||||
const przewoznik: Przewoznik = {
|
||||
DaneIdentyfikacyjne: { NIP: { _text: '12345' } },
|
||||
AdresPrzewoznika: { AdresPol: { Miasto: { _text: 'Warsaw' } } },
|
||||
};
|
||||
const result: any = generatePrzewoznik(przewoznik);
|
||||
|
||||
expect(result[0]).toEqual({ text: 'HEADER:Przewoźnik' });
|
||||
});
|
||||
});
|
||||
21
src/lib-public/generators/FA1/Przewoznik.ts
Normal file
21
src/lib-public/generators/FA1/Przewoznik.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { createHeader, generateTwoColumns } from '../../../shared/PDF-functions';
|
||||
import { Przewoznik } from '../../types/fa1.types';
|
||||
import { generatePodmiotAdres } from './PodmiotAdres';
|
||||
import { generateDaneIdentyfikacyjne } from './PodmiotDaneIdentyfikacyjne';
|
||||
|
||||
export function generatePrzewoznik(przewoznik: Przewoznik | undefined): Content {
|
||||
if (!przewoznik) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
...createHeader('Przewoźnik'),
|
||||
[
|
||||
generateTwoColumns(
|
||||
generateDaneIdentyfikacyjne(przewoznik.DaneIdentyfikacyjne as any),
|
||||
generatePodmiotAdres(przewoznik.AdresPrzewoznika, 'Adres przewoźnika', true, [0, 0, 0, 0]),
|
||||
[0, 0, 0, 8]
|
||||
),
|
||||
],
|
||||
];
|
||||
}
|
||||
239
src/lib-public/generators/FA1/Rabat.spec.ts
Normal file
239
src/lib-public/generators/FA1/Rabat.spec.ts
Normal file
@@ -0,0 +1,239 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generateRabat } from './Rabat';
|
||||
import * as PDFFunctions from '../../../shared/PDF-functions';
|
||||
import { Fa } from '../../types/fa1.types';
|
||||
import FormatTyp, { Position } from '../../../shared/enums/common.enum';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn(),
|
||||
createLabelText: vi.fn(),
|
||||
createSection: vi.fn(),
|
||||
formatText: vi.fn(),
|
||||
generateTwoColumns: vi.fn(),
|
||||
getContentTable: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
}));
|
||||
|
||||
describe(generateRabat.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
const mockInvoice: Fa = {
|
||||
FaWiersz: [
|
||||
{
|
||||
NrWierszaFa: { _text: '1' },
|
||||
P_7: { _text: 'Product 1' },
|
||||
P_8B: { _text: '5' },
|
||||
P_8A: { _text: 'szt' },
|
||||
},
|
||||
],
|
||||
P_15: { _text: '100.00' },
|
||||
} as any;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([]);
|
||||
vi.mocked(PDFFunctions.createHeader).mockReturnValue(['header'] as any);
|
||||
vi.mocked(PDFFunctions.createLabelText).mockReturnValue(['label'] as any);
|
||||
vi.mocked(PDFFunctions.createSection).mockReturnValue('section' as any);
|
||||
vi.mocked(PDFFunctions.formatText).mockReturnValue('formatted' as any);
|
||||
vi.mocked(PDFFunctions.generateTwoColumns).mockReturnValue('columns' as any);
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: null,
|
||||
fieldsWithValue: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should call createHeader with "Rabat"', () => {
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Rabat');
|
||||
});
|
||||
|
||||
it('should call createSection and return result', () => {
|
||||
const mockSection = 'section';
|
||||
vi.mocked(PDFFunctions.createSection).mockReturnValue(mockSection as any);
|
||||
|
||||
const result = generateRabat(mockInvoice);
|
||||
|
||||
expect(PDFFunctions.createSection).toHaveBeenCalledWith(expect.any(Array), true);
|
||||
expect(result).toEqual(mockSection);
|
||||
});
|
||||
|
||||
it('should call getTable with FaWiersz', () => {
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
expect(PDFFunctions.getTable).toHaveBeenCalledWith(mockInvoice.FaWiersze);
|
||||
});
|
||||
|
||||
it('should call createLabelText with discount value', () => {
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Wartość rabatu ogółem: ',
|
||||
mockInvoice.P_15,
|
||||
FormatTyp.Currency,
|
||||
{ alignment: Position.RIGHT }
|
||||
);
|
||||
});
|
||||
|
||||
it('should call getContentTable with correct headers', () => {
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ name: 'NrWierszaFay', 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' }),
|
||||
]),
|
||||
[],
|
||||
'*'
|
||||
);
|
||||
});
|
||||
|
||||
describe('discount text generation', () => {
|
||||
it('should generate text "nie dotyczy" when NrWierszaFa is in fieldsWithValue', () => {
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: null,
|
||||
fieldsWithValue: ['NrWierszaFa', 'P_7'],
|
||||
});
|
||||
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(
|
||||
'Rabat nie dotyczy wszystkich dostaw towarów i wykonanych usług na rzecz tego nabywcy w danym okresie.',
|
||||
FormatTyp.Default
|
||||
);
|
||||
});
|
||||
|
||||
it('should generate text "dotyczy" when NrWierszaFa is not in fieldsWithValue', () => {
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: null,
|
||||
fieldsWithValue: ['P_7', 'P_8B'],
|
||||
});
|
||||
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(
|
||||
'Rabat dotyczy wszystkich dostaw towarów i wykonanych usług na rzecz tego nabywcy w danym okresie.',
|
||||
FormatTyp.Default
|
||||
);
|
||||
});
|
||||
|
||||
it('should call generateTwoColumns with formatted text and empty string', () => {
|
||||
vi.mocked(PDFFunctions.formatText).mockReturnValue('formatted-text' as any);
|
||||
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
expect(PDFFunctions.generateTwoColumns).toHaveBeenCalledWith('formatted-text', '');
|
||||
});
|
||||
});
|
||||
|
||||
describe('table content', () => {
|
||||
it('should add table content when fieldsWithValue is not empty and content exists', () => {
|
||||
const mockTable = { table: 'mock-table' };
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: mockTable as any,
|
||||
fieldsWithValue: ['P_7', 'P_8B'],
|
||||
});
|
||||
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[];
|
||||
expect(sectionCall).toContain(mockTable);
|
||||
});
|
||||
|
||||
it('should not add table content when fieldsWithValue is empty', () => {
|
||||
const mockTable = { table: 'mock-table' };
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: mockTable as any,
|
||||
fieldsWithValue: [],
|
||||
});
|
||||
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[];
|
||||
expect(sectionCall).not.toContain(mockTable);
|
||||
});
|
||||
|
||||
it('should not add table content when content is null', () => {
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: null,
|
||||
fieldsWithValue: ['P_7', 'P_8B'],
|
||||
});
|
||||
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[];
|
||||
expect(sectionCall.every((item: any) => item !== null)).toBe(true);
|
||||
});
|
||||
|
||||
it('should not add table content when both fieldsWithValue is empty and content is null', () => {
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: null,
|
||||
fieldsWithValue: [],
|
||||
});
|
||||
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[];
|
||||
expect(sectionCall.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('result structure', () => {
|
||||
it('should include header in result', () => {
|
||||
vi.mocked(PDFFunctions.createHeader).mockReturnValue(['header-content'] as any);
|
||||
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[];
|
||||
expect(sectionCall).toContain('header-content');
|
||||
});
|
||||
|
||||
it('should include label text in result', () => {
|
||||
vi.mocked(PDFFunctions.createLabelText).mockReturnValue(['label-content'] as any);
|
||||
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[];
|
||||
expect(sectionCall).toContain('label-content');
|
||||
});
|
||||
|
||||
it('should include two columns in result', () => {
|
||||
vi.mocked(PDFFunctions.generateTwoColumns).mockReturnValue('columns-content' as any);
|
||||
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[];
|
||||
expect(sectionCall).toContain('columns-content');
|
||||
});
|
||||
});
|
||||
|
||||
describe('complete integration', () => {
|
||||
it('should generate complete structure with all elements', () => {
|
||||
const mockTable = { table: 'mock-table' };
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: mockTable as any,
|
||||
fieldsWithValue: ['NrWierszaFa', 'P_7'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.createHeader).mockReturnValue(['header'] as any);
|
||||
vi.mocked(PDFFunctions.createLabelText).mockReturnValue(['label'] as any);
|
||||
vi.mocked(PDFFunctions.generateTwoColumns).mockReturnValue('columns' as any);
|
||||
|
||||
generateRabat(mockInvoice);
|
||||
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalled();
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalled();
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalled();
|
||||
expect(PDFFunctions.generateTwoColumns).toHaveBeenCalled();
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalled();
|
||||
expect(PDFFunctions.createSection).toHaveBeenCalled();
|
||||
|
||||
const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0] as any[];
|
||||
expect(sectionCall.length).toBeGreaterThan(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
46
src/lib-public/generators/FA1/Rabat.ts
Normal file
46
src/lib-public/generators/FA1/Rabat.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
createSection,
|
||||
formatText,
|
||||
generateTwoColumns,
|
||||
getContentTable,
|
||||
getTable,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { Fa, FP } from '../../types/fa1.types';
|
||||
import FormatTyp, { Position } from '../../../shared/enums/common.enum';
|
||||
import { TableWithFields } from '../../types/fa1-additional-types';
|
||||
|
||||
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: '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: TableWithFields = getContentTable<(typeof faRows)[0]>(definedHeader, faRows, '*');
|
||||
const isNrWierszaFa: boolean = tabRabat.fieldsWithValue.includes('NrWierszaFa');
|
||||
|
||||
result.push(
|
||||
...createHeader('Rabat'),
|
||||
...createLabelText('Wartość rabatu ogółem: ', invoice.P_15, FormatTyp.Currency, {
|
||||
alignment: Position.RIGHT,
|
||||
}),
|
||||
generateTwoColumns(
|
||||
formatText(
|
||||
`Rabat ${isNrWierszaFa ? 'nie ' : ''}dotyczy wszystkich dostaw towarów i wykonanych usług na rzecz tego nabywcy w danym okresie.`,
|
||||
FormatTyp.Default
|
||||
),
|
||||
''
|
||||
)
|
||||
);
|
||||
if (tabRabat.fieldsWithValue.length > 0 && tabRabat.content) {
|
||||
result.push(tabRabat.content);
|
||||
}
|
||||
|
||||
return createSection(result, true);
|
||||
}
|
||||
235
src/lib-public/generators/FA1/RachubekBankowy.spec.ts
Normal file
235
src/lib-public/generators/FA1/RachubekBankowy.spec.ts
Normal file
@@ -0,0 +1,235 @@
|
||||
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';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn(),
|
||||
createSection: vi.fn(),
|
||||
formatText: vi.fn(),
|
||||
}));
|
||||
|
||||
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('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, 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');
|
||||
});
|
||||
});
|
||||
});
|
||||
74
src/lib-public/generators/FA1/RachunekBankowy.ts
Normal file
74
src/lib-public/generators/FA1/RachunekBankowy.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { Content, ContentTable } from 'pdfmake/interfaces';
|
||||
import { createHeader, createSection, formatText } from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { FP } from '../../types/fa1.types';
|
||||
import { getTypRachunkowWlasnych } from '../../../shared/generators/common/functions';
|
||||
import { DEFAULT_TABLE_LAYOUT } from '../../../shared/consts/const';
|
||||
|
||||
export const generujRachunekBankowy: (accounts?: Record<string, FP>[], title?: string) => Content[] = (
|
||||
accounts?: Record<string, FP>[],
|
||||
title?: string
|
||||
): Content[] => {
|
||||
const result: Content[] = [];
|
||||
|
||||
if (!accounts?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
accounts.forEach((account: Record<string, FP>, index: number): void => {
|
||||
const table: Content[][] = [];
|
||||
const base: Content[] = createHeader(
|
||||
title ? `${title} ${accounts?.length > 1 ? ++index : ''}` : '',
|
||||
[0, 12, 0, 8]
|
||||
);
|
||||
|
||||
if (account.NrRBZagr?._text) {
|
||||
table.push([
|
||||
formatText('Format rachunku', FormatTyp.GrayBoldTitle),
|
||||
formatText('Zagraniczny', FormatTyp.Default),
|
||||
]);
|
||||
} else if (account.NrRBPL?._text) {
|
||||
table.push([
|
||||
formatText('Format rachunku', FormatTyp.GrayBoldTitle),
|
||||
formatText('Polski', FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (account.NrRBPL?._text) {
|
||||
table.push([
|
||||
formatText('Pełny numer rachunku w standardzie NRB', FormatTyp.GrayBoldTitle),
|
||||
formatText(account.NrRBPL?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
if (account.NrRBZagr?._text) {
|
||||
table.push([
|
||||
formatText('Pełny numer rachunku zagranicznego', FormatTyp.GrayBoldTitle),
|
||||
formatText(account.NrRBZagr?._text, FormatTyp.Default),
|
||||
]);
|
||||
}
|
||||
table.push([
|
||||
formatText('Kod SWIFT', FormatTyp.GrayBoldTitle),
|
||||
formatText(account.SWIFT?._text, FormatTyp.Default),
|
||||
]);
|
||||
table.push([
|
||||
formatText('Rachunek własny banku', FormatTyp.GrayBoldTitle),
|
||||
formatText(getTypRachunkowWlasnych(account.RachunekWlasnyBanku), FormatTyp.Default),
|
||||
]);
|
||||
table.push([
|
||||
formatText('Nazwa banku', FormatTyp.GrayBoldTitle),
|
||||
formatText(account.NazwaBanku?._text, FormatTyp.Default),
|
||||
]);
|
||||
result.push([
|
||||
...base,
|
||||
{
|
||||
unbreakable: true,
|
||||
table: {
|
||||
body: table,
|
||||
widths: ['*', 'auto'],
|
||||
},
|
||||
layout: DEFAULT_TABLE_LAYOUT,
|
||||
} as ContentTable,
|
||||
]);
|
||||
});
|
||||
|
||||
return createSection(result, false);
|
||||
};
|
||||
170
src/lib-public/generators/FA1/Szczegoly.spec.ts
Normal file
170
src/lib-public/generators/FA1/Szczegoly.spec.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { generateSzczegoly } from './Szczegoly';
|
||||
import * as PDFFunctions from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { TRodzajFaktury } from '../../../shared/consts/const';
|
||||
import { Fa } from '../../types/fa1.types';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn(),
|
||||
createLabelText: vi.fn(),
|
||||
createLabelTextArray: vi.fn(),
|
||||
createSection: vi.fn(),
|
||||
generateTwoColumns: vi.fn(),
|
||||
getContentTable: vi.fn(),
|
||||
getDifferentColumnsValue: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
getValue: vi.fn(),
|
||||
hasColumnsValue: vi.fn(),
|
||||
hasValue: vi.fn(),
|
||||
}));
|
||||
|
||||
describe(generateSzczegoly.name, () => {
|
||||
let mockFaVat: Fa;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
mockFaVat = {
|
||||
FaWiersze: [],
|
||||
Zamowienie: { ZamowienieWiersz: [] },
|
||||
RodzajFaktury: TRodzajFaktury.VAT,
|
||||
OkresFa: { P_6_Od: { _text: '' }, P_6_Do: { _text: '' } },
|
||||
P_1: { _text: '2024-01-01' },
|
||||
P_1M: { _text: 'Warsaw' },
|
||||
OkresFaKorygowanej: { _text: '' },
|
||||
P_6: { _text: '2024-01-15' },
|
||||
KodWaluty: { _text: 'PLN' },
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([]);
|
||||
vi.mocked(PDFFunctions.createHeader).mockReturnValue(['header'] as any);
|
||||
vi.mocked(PDFFunctions.createLabelText).mockReturnValue('label' as any);
|
||||
vi.mocked(PDFFunctions.createLabelTextArray).mockReturnValue('labelArray' as any);
|
||||
vi.mocked(PDFFunctions.createSection).mockReturnValue('section' as any);
|
||||
vi.mocked(PDFFunctions.generateTwoColumns).mockReturnValue('columns' as any);
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({ content: null, fieldsWithValue: [] });
|
||||
vi.mocked(PDFFunctions.getDifferentColumnsValue).mockReturnValue([]);
|
||||
vi.mocked(PDFFunctions.getValue).mockReturnValue('PLN');
|
||||
vi.mocked(PDFFunctions.hasColumnsValue).mockReturnValue(false);
|
||||
vi.mocked(PDFFunctions.hasValue).mockReturnValue(false);
|
||||
});
|
||||
|
||||
it('should create header and section', () => {
|
||||
const result = generateSzczegoly(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Szczegóły');
|
||||
expect(PDFFunctions.createSection).toHaveBeenCalledWith(expect.any(Array), true);
|
||||
expect(result).toEqual('section');
|
||||
});
|
||||
|
||||
it('should call getTable for FaWiersze and ZamowienieWiersz', () => {
|
||||
generateSzczegoly(mockFaVat);
|
||||
expect(PDFFunctions.getTable).toHaveBeenCalledWith(mockFaVat.FaWiersze?.FaWiersz);
|
||||
expect(PDFFunctions.getTable).toHaveBeenCalledWith(mockFaVat.Zamowienie?.ZamowienieWiersz);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
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
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('P_6 scope', () => {
|
||||
it('creates scope array when P_6_Od and P_6_Do exist', () => {
|
||||
const data = {
|
||||
...mockFaVat,
|
||||
OkresFa: { P_6_Od: { _text: '2024-01-01' }, P_6_Do: { _text: '2024-01-31' } },
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.hasValue).mockImplementation(
|
||||
(value: any) => value === data.OkresFa.P_6_Od || value === data.OkresFa.P_6_Do
|
||||
);
|
||||
|
||||
generateSzczegoly(data);
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).toHaveBeenCalledWith([
|
||||
{ value: 'Data dokonania lub zakończenia dostawy towarów lub wykonania usługi: od ' },
|
||||
{ value: data.OkresFa.P_6_Od, formatTyp: FormatTyp.Value },
|
||||
{ value: ' do ' },
|
||||
{ value: data.OkresFa.P_6_Do, formatTyp: FormatTyp.Value },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ceny labels', () => {
|
||||
it('adds netto label when P_11 exists', () => {
|
||||
vi.mocked(PDFFunctions.hasColumnsValue).mockImplementation((col) => col === 'P_11');
|
||||
generateSzczegoly(mockFaVat);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Faktura wystawiona w cenach: ', 'netto');
|
||||
});
|
||||
|
||||
it('adds brutto label when P_11 does not exist', () => {
|
||||
vi.mocked(PDFFunctions.hasColumnsValue).mockReturnValue(false);
|
||||
generateSzczegoly(mockFaVat);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Faktura wystawiona w cenach: ', 'brutto');
|
||||
});
|
||||
|
||||
it('adds currency label', () => {
|
||||
generateSzczegoly(mockFaVat);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Kod waluty: ', mockFaVat.KodWaluty);
|
||||
});
|
||||
});
|
||||
|
||||
describe('P_12_XII label', () => {
|
||||
it('adds OSS label when P_12_XII exists', () => {
|
||||
vi.mocked(PDFFunctions.hasColumnsValue).mockImplementation((col) => col === 'P_12_XII');
|
||||
generateSzczegoly(mockFaVat);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Procedura One Stop Shop', ' ');
|
||||
});
|
||||
});
|
||||
|
||||
describe('kurs waluty', () => {
|
||||
it('adds currency rate when currency is not PLN and common rate exists', () => {
|
||||
const data = { ...mockFaVat, KodWaluty: { _text: 'EUR' }, Zamowienie: { ZamowienieWiersz: [] } } as any;
|
||||
vi.mocked(PDFFunctions.hasValue).mockReturnValue(true);
|
||||
vi.mocked(PDFFunctions.getValue).mockReturnValue('EUR');
|
||||
vi.mocked(PDFFunctions.getDifferentColumnsValue).mockReturnValue([{ value: '4.50' }]);
|
||||
generateSzczegoly(data);
|
||||
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Kurs waluty wspólny dla wszystkich wierszy faktury',
|
||||
' '
|
||||
);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Kurs waluty: ', '4.50', FormatTyp.Currency6);
|
||||
});
|
||||
|
||||
it('does not add currency rate when PLN', () => {
|
||||
vi.mocked(PDFFunctions.getValue).mockReturnValue('PLN');
|
||||
generateSzczegoly(mockFaVat);
|
||||
const calls = vi.mocked(PDFFunctions.createLabelText).mock.calls;
|
||||
const currencyCall = calls.find((call) => call[0] === 'Kurs waluty: ');
|
||||
expect(currencyCall).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('columns distribution', () => {
|
||||
it('calls generateTwoColumns with labels split', () => {
|
||||
generateSzczegoly(mockFaVat);
|
||||
expect(PDFFunctions.generateTwoColumns).toHaveBeenCalledWith(expect.any(Array), expect.any(Array));
|
||||
});
|
||||
});
|
||||
|
||||
describe('faktura zaliczkowa', () => {
|
||||
it('generates table when data exists', () => {
|
||||
const data = { ...mockFaVat, NrFaZaliczkowej: [{ _text: 'FA001' }] } as any;
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValueOnce([{ _text: 'FA001' }] as any);
|
||||
generateSzczegoly(data);
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
168
src/lib-public/generators/FA1/Szczegoly.ts
Normal file
168
src/lib-public/generators/FA1/Szczegoly.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
createLabelTextArray,
|
||||
createSection,
|
||||
generateTwoColumns,
|
||||
getContentTable,
|
||||
getDifferentColumnsValue,
|
||||
getTable,
|
||||
getValue,
|
||||
hasColumnsValue,
|
||||
hasValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { TRodzajFaktury } from '../../../shared/consts/const';
|
||||
import { Fa, FP } from '../../types/fa1.types';
|
||||
import { DifferentValues, TypesOfValues } from '../../../shared/types/universal.types';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { TableWithFields } from '../../types/fa1-additional-types';
|
||||
|
||||
export function generateSzczegoly(faVat: Fa): Content[] {
|
||||
const faWiersze: Record<string, FP>[] = getTable(faVat.FaWiersze?.FaWiersz);
|
||||
const zamowieniaWiersze: Record<string, FP>[] = getTable(faVat.Zamowienie?.ZamowienieWiersz);
|
||||
const LabelP_6: string =
|
||||
faVat.RodzajFaktury == TRodzajFaktury.ZAL || faVat.RodzajFaktury == TRodzajFaktury.KOR_ZAL
|
||||
? 'Data otrzymania zapłaty: '
|
||||
: 'Data dokonania lub zakończenia dostawy towarów lub wykonania usługi: ';
|
||||
|
||||
const P_6Scope: Content[] = generateP_6Scope(faVat.OkresFa?.P_6_Od, faVat.OkresFa?.P_6_Do);
|
||||
|
||||
const cenyLabel1: Content[] = [];
|
||||
const cenyLabel2: Content[] = [];
|
||||
|
||||
if (!(faWiersze.length > 0 || zamowieniaWiersze.length > 0)) {
|
||||
const Any_P_11: boolean =
|
||||
hasColumnsValue('P_11', faWiersze) || hasColumnsValue('P_11', zamowieniaWiersze);
|
||||
|
||||
if (Any_P_11) {
|
||||
cenyLabel1.push(createLabelText('Faktura wystawiona w cenach: ', 'netto'));
|
||||
} else {
|
||||
cenyLabel1.push(createLabelText('Faktura wystawiona w cenach: ', 'brutto'));
|
||||
}
|
||||
cenyLabel2.push(createLabelText('Kod waluty: ', faVat.KodWaluty));
|
||||
}
|
||||
|
||||
const P_12_XIILabel: Content[] = [];
|
||||
|
||||
if (hasColumnsValue('P_12_XII', faWiersze) || hasColumnsValue('P_12_XII', zamowieniaWiersze)) {
|
||||
P_12_XIILabel.push(createLabelText('Procedura One Stop Shop', ' '));
|
||||
}
|
||||
|
||||
const kodWalutyLabel1: Content[] = [];
|
||||
const kodWalutyLabel2: Content[] = [];
|
||||
|
||||
if (hasValue(faVat.KodWaluty) && getValue(faVat.KodWaluty) != 'PLN') {
|
||||
if (faVat.Zamowienie?.ZamowienieWiersz?.length) {
|
||||
const Common_KursWaluty: DifferentValues[] = getDifferentColumnsValue(
|
||||
'KursWalutyZ',
|
||||
faVat.Zamowienie?.ZamowienieWiersz
|
||||
);
|
||||
|
||||
if (Common_KursWaluty.length === 1) {
|
||||
kodWalutyLabel1.push(createLabelText('Kurs waluty wspólny dla wszystkich wierszy faktury', ' '));
|
||||
kodWalutyLabel2.push(
|
||||
createLabelText('Kurs waluty: ', Common_KursWaluty[0].value, FormatTyp.Currency6)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const Common_KursWaluty: DifferentValues[] = getDifferentColumnsValue('KursWaluty', faWiersze);
|
||||
|
||||
if (Common_KursWaluty.length === 1) {
|
||||
kodWalutyLabel1.push(createLabelText('Kurs waluty wspólny dla wszystkich wierszy faktury', ' '));
|
||||
kodWalutyLabel2.push(
|
||||
createLabelText('Kurs waluty: ', Common_KursWaluty[0].value, FormatTyp.Currency6)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
const tpLabel1: Content[] = [];
|
||||
const tpLabel2: 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('Miejsce wystawienia: ', faVat.P_1M),
|
||||
createLabelText('Okres, którego dotyczy rabat: ', faVat.OkresFaKorygowanej),
|
||||
createLabelText(LabelP_6, faVat.P_6),
|
||||
P_6Scope,
|
||||
cenyLabel1,
|
||||
cenyLabel2,
|
||||
P_12_XIILabel,
|
||||
kodWalutyLabel1,
|
||||
kodWalutyLabel2,
|
||||
tpLabel1,
|
||||
tpLabel2,
|
||||
].filter((el: Content[]): boolean => el.length > 0);
|
||||
const columns1: Content[] = [];
|
||||
const columns2: Content[] = [];
|
||||
|
||||
forColumns.forEach((tab: Content[], index: number): void => {
|
||||
if (index % 2) {
|
||||
columns2.push(tab);
|
||||
} else {
|
||||
columns1.push(tab);
|
||||
}
|
||||
});
|
||||
const table: Content[] = [
|
||||
...createHeader('Szczegóły'),
|
||||
generateTwoColumns(columns1, columns2),
|
||||
...generateFakturaZaliczkowa(getTable(faVat.NrFaZaliczkowej)),
|
||||
];
|
||||
|
||||
return createSection(table, true);
|
||||
}
|
||||
|
||||
function generateP_6Scope(P_6_Od: TypesOfValues, P_6_Do: TypesOfValues): Content[] {
|
||||
const table: Content[] = [];
|
||||
|
||||
if (hasValue(P_6_Od) && hasValue(P_6_Do)) {
|
||||
table.push(
|
||||
createLabelTextArray([
|
||||
{
|
||||
value: 'Data dokonania lub zakończenia dostawy towarów lub wykonania usługi: od ',
|
||||
},
|
||||
{ value: P_6_Od, formatTyp: FormatTyp.Value },
|
||||
{ value: ' do ' },
|
||||
{ value: P_6_Do, formatTyp: FormatTyp.Value },
|
||||
])
|
||||
);
|
||||
} else if (hasValue(P_6_Od)) {
|
||||
table.push(
|
||||
createLabelText('Data dokonania lub zakończenia dostawy towarów lub wykonania usługi: od ', P_6_Od)
|
||||
);
|
||||
} else if (hasValue(P_6_Do)) {
|
||||
table.push(
|
||||
createLabelText('Data dokonania lub zakończenia dostawy towarów lub wykonania usługi: do ', P_6_Do)
|
||||
);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
function generateFakturaZaliczkowa(fakturaZaliczkowa: FP[] | undefined): Content[] {
|
||||
if (!fakturaZaliczkowa) {
|
||||
return [];
|
||||
}
|
||||
const table: Content[] = [];
|
||||
|
||||
const fakturaZaliczkowaHeader: HeaderDefine[] = [
|
||||
{
|
||||
name: '',
|
||||
title: 'Numery wcześniejszych faktur zaliczkowych',
|
||||
format: FormatTyp.Default,
|
||||
},
|
||||
];
|
||||
|
||||
const tableFakturaZaliczkowa: TableWithFields = getContentTable<(typeof fakturaZaliczkowa)[0]>(
|
||||
fakturaZaliczkowaHeader,
|
||||
fakturaZaliczkowa,
|
||||
'50%',
|
||||
[0, 4, 0, 0]
|
||||
);
|
||||
|
||||
if (tableFakturaZaliczkowa.content) {
|
||||
table.push(tableFakturaZaliczkowa.content);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
170
src/lib-public/generators/FA1/Transport.spec.ts
Normal file
170
src/lib-public/generators/FA1/Transport.spec.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generateTransport } from './Transport';
|
||||
import * as PDFFunctions from '../../../shared/PDF-functions';
|
||||
import * as PrzewoznikModule from './Przewoznik';
|
||||
import * as CommonFunctions from '../../../shared/generators/common/functions';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn(),
|
||||
createLabelText: vi.fn(),
|
||||
createSection: vi.fn(),
|
||||
createSubHeader: vi.fn(),
|
||||
generateTwoColumns: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
hasValue: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('./Przewoznik', () => ({
|
||||
generatePrzewoznik: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../../../shared/generators/common/functions', () => ({
|
||||
getDateTimeWithoutSeconds: vi.fn(),
|
||||
getRodzajTransportuString: vi.fn(),
|
||||
getOpisTransportuString: vi.fn(),
|
||||
}));
|
||||
|
||||
describe(generateTransport.name, () => {
|
||||
let mockTransport: any;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockTransport = {
|
||||
RodzajTransportu: { _text: '1' },
|
||||
TransportInny: { _text: '0' },
|
||||
OpisInnegoTransportu: { _text: '' },
|
||||
NrZleceniaTransportu: { _text: 'TR001' },
|
||||
OpisLadunku: { _text: 'Goods' },
|
||||
LadunekInny: { _text: '0' },
|
||||
OpisInnegoLadunku: { _text: '' },
|
||||
JednostkaOpakowania: { _text: 'Box' },
|
||||
DataGodzRozpTransportu: { _text: '2024-01-01T10:00:00' },
|
||||
DataGodzZakTransportu: { _text: '2024-01-02T15:00:00' },
|
||||
Przewoznik: {},
|
||||
WysylkaZ: {
|
||||
AdresL1: { _text: 'Street 1' },
|
||||
AdresL2: { _text: 'City 1' },
|
||||
KodKraju: { _text: 'PL' },
|
||||
GLN: { _text: '123456' },
|
||||
},
|
||||
WysylkaDo: {
|
||||
AdresL1: { _text: 'Street 2' },
|
||||
AdresL2: { _text: 'City 2' },
|
||||
KodKraju: { _text: 'DE' },
|
||||
GLN: { _text: '789012' },
|
||||
},
|
||||
WysylkaPrzez: [],
|
||||
};
|
||||
|
||||
vi.mocked(PDFFunctions.createHeader).mockReturnValue('header' as any);
|
||||
vi.mocked(PDFFunctions.createLabelText).mockReturnValue('label' as any);
|
||||
vi.mocked(PDFFunctions.createSection).mockReturnValue('section' as any);
|
||||
vi.mocked(PDFFunctions.createSubHeader).mockReturnValue('subheader' as any);
|
||||
vi.mocked(PDFFunctions.generateTwoColumns).mockReturnValue('columns' as any);
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([]);
|
||||
vi.mocked(PDFFunctions.hasValue).mockReturnValue(true);
|
||||
vi.mocked(PrzewoznikModule.generatePrzewoznik).mockReturnValue('przewoznik' as any);
|
||||
vi.mocked(CommonFunctions.getDateTimeWithoutSeconds).mockReturnValue('2024-01-01 10:00');
|
||||
vi.mocked(CommonFunctions.getRodzajTransportuString).mockReturnValue('Road');
|
||||
vi.mocked(CommonFunctions.getOpisTransportuString).mockReturnValue('Opis');
|
||||
});
|
||||
|
||||
it('should return a section', () => {
|
||||
const result = generateTransport(mockTransport);
|
||||
expect(PDFFunctions.createSection).toHaveBeenCalledWith(expect.any(Array), true);
|
||||
expect(result).toBe('section');
|
||||
});
|
||||
|
||||
it('should handle RodzajTransportu', () => {
|
||||
generateTransport(mockTransport);
|
||||
expect(CommonFunctions.getRodzajTransportuString).toHaveBeenCalledWith(mockTransport.RodzajTransportu);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Rodzaj transportu: ', 'Road');
|
||||
});
|
||||
|
||||
it('should handle TransportInny', () => {
|
||||
const data = {
|
||||
...mockTransport,
|
||||
RodzajTransportu: { _text: '' },
|
||||
TransportInny: { _text: '1' },
|
||||
OpisInnegoTransportu: { _text: 'Custom transport' },
|
||||
};
|
||||
generateTransport(data);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Rodzaj transportu: ', 'Transport inny');
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Rodzaj transportu: ', 'Transport inny');
|
||||
});
|
||||
|
||||
it('should handle Dane transportu', () => {
|
||||
generateTransport(mockTransport);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Numer zlecenia transportu: ',
|
||||
mockTransport.NrZleceniaTransportu
|
||||
);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Opis ładunku: ', 'Opis');
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Jednostka opakowania: ',
|
||||
mockTransport.JednostkaOpakowania
|
||||
);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data i godzina rozpoczęcia transportu: ',
|
||||
'2024-01-01 10:00'
|
||||
);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Data i godzina zakończenia transportu: ',
|
||||
'2024-01-01 10:00'
|
||||
);
|
||||
expect(PDFFunctions.createSubHeader).toHaveBeenCalledWith('Dane transportu', [0, 0, 0, 0]);
|
||||
});
|
||||
|
||||
it('should call generatePrzewoznik', () => {
|
||||
generateTransport(mockTransport);
|
||||
expect(PrzewoznikModule.generatePrzewoznik).toHaveBeenCalledWith(mockTransport.Przewoznik);
|
||||
});
|
||||
|
||||
it('should handle WysylkaZ and WysylkaDo', () => {
|
||||
generateTransport(mockTransport);
|
||||
expect(PDFFunctions.createSubHeader).toHaveBeenCalledWith('Adres miejsca wysyłki', [0, 0, 0, 0]);
|
||||
expect(PDFFunctions.createSubHeader).toHaveBeenCalledWith(
|
||||
'Adres miejsca docelowego, do którego został zlecony transport',
|
||||
[0, 0, 0, 0]
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle WysylkaPrzez', () => {
|
||||
const data = {
|
||||
...mockTransport,
|
||||
WysylkaPrzez: [
|
||||
{
|
||||
AdresL1: { _text: 'Street 3' },
|
||||
AdresL2: { _text: 'City 3' },
|
||||
KodKraju: { _text: 'FR' },
|
||||
GLN: { _text: '345678' },
|
||||
},
|
||||
],
|
||||
};
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue(data.WysylkaPrzez as any);
|
||||
generateTransport(data);
|
||||
expect(PDFFunctions.createSubHeader).toHaveBeenCalledWith('Adres pośredni wysyłki', [0, 4, 0, 0]);
|
||||
});
|
||||
|
||||
it('should call generateTwoColumns for main sections and wysylka', () => {
|
||||
generateTransport(mockTransport);
|
||||
expect(PDFFunctions.generateTwoColumns).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add header for Transport and Wysyłka', () => {
|
||||
generateTransport(mockTransport);
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Transport');
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Wysyłka');
|
||||
});
|
||||
|
||||
it('should handle full integration with all fields', () => {
|
||||
const data = {
|
||||
...mockTransport,
|
||||
LadunekInny: { _text: '1' },
|
||||
OpisInnegoLadunku: { _text: 'Custom cargo' },
|
||||
};
|
||||
generateTransport(data);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Opis ładunku: ', 'Ładunek inny');
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Rodzaj transportu: ', 'Road');
|
||||
});
|
||||
});
|
||||
97
src/lib-public/generators/FA1/Transport.ts
Normal file
97
src/lib-public/generators/FA1/Transport.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
createSection,
|
||||
createSubHeader,
|
||||
generateTwoColumns,
|
||||
getTable,
|
||||
hasValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { Transport } from '../../types/fa1.types';
|
||||
import {
|
||||
getDateTimeWithoutSeconds,
|
||||
getOpisTransportuString,
|
||||
getRodzajTransportuString,
|
||||
} from '../../../shared/generators/common/functions';
|
||||
import { generateAdres } from './Adres';
|
||||
import { generatePrzewoznik } from './Przewoznik';
|
||||
|
||||
export function generateTransport(transport: Transport, index?: number | null): Content {
|
||||
const table: Content[] = [];
|
||||
const columns = {
|
||||
transport: [] as Content[],
|
||||
dane: [] as Content[],
|
||||
wysylkaZ: [] as Content[],
|
||||
wysylkaDo: [] as Content[],
|
||||
wysylkaPrzez: [] as Content[],
|
||||
};
|
||||
|
||||
table.push(createHeader(index ? `Transport ${index}` : 'Transport'));
|
||||
if (transport.RodzajTransportu?._text) {
|
||||
columns.transport.push(
|
||||
createLabelText('Rodzaj transportu: ', getRodzajTransportuString(transport.RodzajTransportu))
|
||||
);
|
||||
} else if (transport.TransportInny?._text == '1' && transport.OpisInnegoTransportu?._text) {
|
||||
columns.transport.push(createLabelText('Rodzaj transportu: ', 'Transport inny'));
|
||||
columns.transport.push(
|
||||
createLabelText('Opis innego rodzaju transportu: ', transport.OpisInnegoTransportu)
|
||||
);
|
||||
}
|
||||
columns.dane.push(createLabelText('Numer zlecenia transportu: ', transport.NrZleceniaTransportu));
|
||||
if (hasValue(transport.OpisLadunku)) {
|
||||
columns.dane.push(createLabelText('Opis ładunku: ', getOpisTransportuString(transport.OpisLadunku)));
|
||||
if (transport.LadunekInny?._text === '1' && transport.OpisInnegoLadunku?._text) {
|
||||
columns.dane.push(createLabelText('Opis ładunku: ', 'Ładunek inny'));
|
||||
columns.dane.push(createLabelText('Opis innego ładunku: ', transport.OpisInnegoLadunku));
|
||||
}
|
||||
}
|
||||
columns.dane.push(createLabelText('Jednostka opakowania: ', transport.JednostkaOpakowania));
|
||||
columns.dane.push(
|
||||
createLabelText(
|
||||
'Data i godzina rozpoczęcia transportu: ',
|
||||
getDateTimeWithoutSeconds(transport.DataGodzRozpTransportu)
|
||||
)
|
||||
);
|
||||
columns.dane.push(
|
||||
createLabelText(
|
||||
'Data i godzina zakończenia transportu: ',
|
||||
getDateTimeWithoutSeconds(transport.DataGodzZakTransportu)
|
||||
)
|
||||
);
|
||||
if (columns.dane.length > 0) {
|
||||
columns.dane.unshift(createSubHeader('Dane transportu', [0, 0, 0, 0]));
|
||||
}
|
||||
table.push(generateTwoColumns(columns.transport, columns.dane));
|
||||
|
||||
table.push(generatePrzewoznik(transport.Przewoznik));
|
||||
|
||||
if (transport.WysylkaZ) {
|
||||
columns.wysylkaZ.push(createSubHeader('Adres miejsca wysyłki', [0, 0, 0, 0]));
|
||||
columns.wysylkaZ.push(generateAdres(transport.WysylkaZ));
|
||||
}
|
||||
|
||||
if (transport.WysylkaDo) {
|
||||
columns.wysylkaDo.push(
|
||||
createSubHeader('Adres miejsca docelowego, do którego został zlecony transport', [0, 0, 0, 0])
|
||||
);
|
||||
columns.wysylkaDo.push(generateAdres(transport.WysylkaDo));
|
||||
}
|
||||
|
||||
const wysylkaPrzez = getTable(transport.WysylkaPrzez);
|
||||
|
||||
wysylkaPrzez.forEach((adres, index) => {
|
||||
if (index) {
|
||||
columns.wysylkaPrzez.push('\n');
|
||||
}
|
||||
columns.wysylkaPrzez.push(createSubHeader('Adres pośredni wysyłki', [0, 4, 0, 0]));
|
||||
columns.wysylkaPrzez.push(generateAdres(adres));
|
||||
});
|
||||
|
||||
if (transport.WysylkaZ || transport.WysylkaDo || transport.WysylkaPrzez?.length) {
|
||||
table.push(createHeader('Wysyłka'));
|
||||
table.push(generateTwoColumns(columns.wysylkaZ, columns.wysylkaDo));
|
||||
table.push(generateTwoColumns(columns.wysylkaPrzez, []));
|
||||
}
|
||||
return createSection(table, true);
|
||||
}
|
||||
517
src/lib-public/generators/FA1/WarunkiTransakcji.spec.ts
Normal file
517
src/lib-public/generators/FA1/WarunkiTransakcji.spec.ts
Normal file
@@ -0,0 +1,517 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generateWarunkiTransakcji } from './WarunkiTransakcji';
|
||||
import * as PDFFunctions from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { WarunkiTransakcji } from '../../types/fa1.types';
|
||||
import * as TransportModule from './Transport';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn(),
|
||||
createLabelText: vi.fn(),
|
||||
createSection: vi.fn(),
|
||||
createSubHeader: vi.fn(),
|
||||
formatText: vi.fn(),
|
||||
generateTwoColumns: vi.fn(),
|
||||
getContentTable: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('./Transport', () => ({
|
||||
generateTransport: vi.fn(),
|
||||
}));
|
||||
|
||||
describe(generateWarunkiTransakcji.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('when warunkiTransakcji is undefined', () => {
|
||||
it('should return empty array', () => {
|
||||
const result = generateWarunkiTransakcji(undefined);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when warunkiTransakcji is defined', () => {
|
||||
const mockWarunkiTransakcji: WarunkiTransakcji = {
|
||||
Umowy: [],
|
||||
Zamowienia: [],
|
||||
NrPartiiTowaru: [],
|
||||
WalutaUmowna: { _text: '' },
|
||||
KursUmowny: { _text: '' },
|
||||
WarunkiDostawy: { _text: '' },
|
||||
PodmiotPosredniczacy: { _text: '0' },
|
||||
} as any;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([]);
|
||||
vi.mocked(PDFFunctions.createHeader).mockReturnValue('header' as any);
|
||||
vi.mocked(PDFFunctions.createSection).mockReturnValue('section' as any);
|
||||
vi.mocked(PDFFunctions.createLabelText).mockReturnValue('label' as any);
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: null,
|
||||
fieldsWithValue: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should call createHeader with "Warunki transakcji"', () => {
|
||||
generateWarunkiTransakcji(mockWarunkiTransakcji);
|
||||
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Warunki transakcji', [0, 8, 0, 4]);
|
||||
});
|
||||
|
||||
it('should call getTable for Umowy, Zamowienia and NrPartiiTowaru', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
Umowy: [{ DataUmowy: { _text: '2024-01-01' } }],
|
||||
Zamowienia: [{ DataZamowienia: { _text: '2024-01-02' } }],
|
||||
NrPartiiTowaru: [{ _text: 'BATCH001' }],
|
||||
} as any;
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.getTable).toHaveBeenCalledWith(data.Umowy);
|
||||
expect(PDFFunctions.getTable).toHaveBeenCalledWith(data.Zamowienia);
|
||||
expect(PDFFunctions.getTable).toHaveBeenCalledWith(data.NrPartiiTowaru);
|
||||
});
|
||||
|
||||
it('should call createSection with table array', () => {
|
||||
generateWarunkiTransakcji(mockWarunkiTransakcji);
|
||||
|
||||
expect(PDFFunctions.createSection).toHaveBeenCalledWith(expect.any(Array), true);
|
||||
});
|
||||
|
||||
it('should return result from createSection', () => {
|
||||
const mockSection = { section: 'test' };
|
||||
vi.mocked(PDFFunctions.createSection).mockReturnValue(mockSection as any);
|
||||
|
||||
const result = generateWarunkiTransakcji(mockWarunkiTransakcji);
|
||||
|
||||
expect(result).toEqual(mockSection);
|
||||
});
|
||||
|
||||
describe('umowy section', () => {
|
||||
it('should create umowy section when umowy exist', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
Umowy: [{ DataUmowy: { _text: '2024-01-01' }, NrUmowy: { _text: 'U001' } }],
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockImplementation((field: any) => {
|
||||
if (field === data.Umowy)
|
||||
return [
|
||||
{
|
||||
DataUmowy: { _text: '2024-01-01' },
|
||||
NrUmowy: { _text: 'U001' },
|
||||
},
|
||||
] as any;
|
||||
return [];
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValueOnce({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['DataUmowy', 'NrUmowy'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.createSubHeader).mockReturnValue('subheader' as any);
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.createSubHeader).toHaveBeenCalledWith('Umowa');
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ name: 'DataUmowy', title: 'Data umowy' }),
|
||||
expect.objectContaining({ name: 'NrUmowy', title: 'Numer umowy' }),
|
||||
]),
|
||||
expect.any(Array),
|
||||
'*'
|
||||
);
|
||||
});
|
||||
|
||||
it('should not create umowy section when umowy are empty', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([]);
|
||||
vi.mocked(PDFFunctions.createSubHeader).mockClear();
|
||||
|
||||
generateWarunkiTransakcji(mockWarunkiTransakcji);
|
||||
|
||||
expect(PDFFunctions.createSubHeader).not.toHaveBeenCalledWith('Umowa');
|
||||
});
|
||||
});
|
||||
|
||||
describe('zamowienia section', () => {
|
||||
it('should create zamowienia section when zamowienia exist', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
Zamowienia: [{ DataZamowienia: { _text: '2024-01-02' }, NrZamowienia: { _text: 'Z001' } }],
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockImplementation((field: any) => {
|
||||
if (field === data.Zamowienia)
|
||||
return [
|
||||
{
|
||||
DataZamowienia: { _text: '2024-01-02' },
|
||||
NrZamowienia: { _text: 'Z001' },
|
||||
},
|
||||
] as any;
|
||||
return [];
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValueOnce({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['DataZamowienia', 'NrZamowienia'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.createSubHeader).mockReturnValue('subheader' as any);
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.createSubHeader).toHaveBeenCalledWith('Zamówienie');
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ name: 'DataZamowienia', title: 'Data zamówienia' }),
|
||||
expect.objectContaining({ name: 'NrZamowienia', title: 'Numer zamówienia' }),
|
||||
]),
|
||||
expect.any(Array),
|
||||
'*'
|
||||
);
|
||||
});
|
||||
|
||||
it('should not create zamowienia section when zamowienia are empty', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([]);
|
||||
vi.mocked(PDFFunctions.createSubHeader).mockClear();
|
||||
|
||||
generateWarunkiTransakcji(mockWarunkiTransakcji);
|
||||
|
||||
expect(PDFFunctions.createSubHeader).not.toHaveBeenCalledWith('Zamówienie');
|
||||
});
|
||||
|
||||
it('should not create zamowienia section when fieldsWithValue is empty', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
Zamowienia: [{ DataZamowienia: { _text: '' } }],
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockImplementation((field: any) => {
|
||||
if (field === data.Zamowienia) return [{ DataZamowienia: { _text: '' } }] as any;
|
||||
return [];
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValueOnce({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: [],
|
||||
});
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.generateTwoColumns).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('two columns generation', () => {
|
||||
it('should generate two columns when umowy exist', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
Umowy: [{ DataUmowy: { _text: '2024-01-01' } }],
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockImplementation((field: any) => {
|
||||
if (field === data.Umowy) return [{ DataUmowy: { _text: '2024-01-01' } }] as any;
|
||||
return [];
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValueOnce({
|
||||
content: { table: 'umowy' } as any,
|
||||
fieldsWithValue: ['DataUmowy'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.createSubHeader).mockReturnValue('subheader' as any);
|
||||
vi.mocked(PDFFunctions.generateTwoColumns).mockReturnValue('twoColumns' as any);
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.generateTwoColumns).toHaveBeenCalledWith(
|
||||
expect.arrayContaining(['subheader', { table: 'umowy' }]),
|
||||
[]
|
||||
);
|
||||
});
|
||||
|
||||
it('should generate two columns when zamowienia exist', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
Zamowienia: [{ DataZamowienia: { _text: '2024-01-02' } }],
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockImplementation((field: any) => {
|
||||
if (field === data.Zamowienia) return [{ DataZamowienia: { _text: '2024-01-02' } }] as any;
|
||||
return [];
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValueOnce({
|
||||
content: { table: 'zamowienia' } as any,
|
||||
fieldsWithValue: ['DataZamowienia'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.createSubHeader).mockReturnValue('subheader' as any);
|
||||
vi.mocked(PDFFunctions.generateTwoColumns).mockReturnValue('twoColumns' as any);
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.generateTwoColumns).toHaveBeenCalledWith(
|
||||
[],
|
||||
expect.arrayContaining(['subheader', { table: 'zamowienia' }])
|
||||
);
|
||||
});
|
||||
|
||||
it('should not generate two columns when both umowy and zamowienia are empty', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([]);
|
||||
|
||||
generateWarunkiTransakcji(mockWarunkiTransakcji);
|
||||
|
||||
expect(PDFFunctions.generateTwoColumns).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('waluta umowna section', () => {
|
||||
it('should create waluta umowna section when WalutaUmowna exists', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
WalutaUmowna: { _text: 'EUR' },
|
||||
KursUmowny: { _text: '' },
|
||||
} as any;
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Waluta umowna i kurs umowny', [0, 8, 0, 4]);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Waluta umowna: ', data.WalutaUmowna);
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith('Kurs umowny: ', data.KursUmowny);
|
||||
});
|
||||
|
||||
it('should create waluta umowna section when KursUmowny exists', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
WalutaUmowna: { _text: '' },
|
||||
KursUmowny: { _text: '4.50' },
|
||||
} as any;
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Waluta umowna i kurs umowny', [0, 8, 0, 4]);
|
||||
});
|
||||
|
||||
it('should not create waluta umowna section when both are empty', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
WalutaUmowna: { _text: '' },
|
||||
KursUmowny: { _text: '' },
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.createHeader).mockClear();
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledTimes(1);
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Warunki transakcji', [0, 8, 0, 4]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('partia towaru section', () => {
|
||||
it('should create partia towaru section when NrPartiiTowaru exists', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
NrPartiiTowaru: [{ _text: 'BATCH001' }],
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockImplementation((field: any) => {
|
||||
if (field === data.NrPartiiTowaru) return [{ _text: 'BATCH001' }] as any;
|
||||
return [];
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValueOnce({
|
||||
content: { table: 'partia' } as any,
|
||||
fieldsWithValue: ['_text'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.generateTwoColumns).mockReturnValue('twoColumns' as any);
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([expect.objectContaining({ name: '', title: 'Numer partii towaru' })]),
|
||||
expect.any(Array),
|
||||
'*',
|
||||
[0, 4]
|
||||
);
|
||||
expect(PDFFunctions.generateTwoColumns).toHaveBeenCalledWith({ table: 'partia' }, ' ');
|
||||
});
|
||||
|
||||
it('should not create partia towaru section when NrPartiiTowaru is empty', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([]);
|
||||
|
||||
const callCountBefore = vi.mocked(PDFFunctions.generateTwoColumns).mock.calls.length;
|
||||
|
||||
generateWarunkiTransakcji(mockWarunkiTransakcji);
|
||||
|
||||
expect(vi.mocked(PDFFunctions.generateTwoColumns).mock.calls.length).toBe(callCountBefore);
|
||||
});
|
||||
});
|
||||
|
||||
describe('warunki dostawy', () => {
|
||||
it('should add warunki dostawy label', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
WarunkiDostawy: { _text: 'FOB' },
|
||||
} as any;
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.createLabelText).toHaveBeenCalledWith(
|
||||
'Warunki dostawy towarów: ',
|
||||
data.WarunkiDostawy,
|
||||
FormatTyp.MarginTop4
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('podmiot posredniczacy', () => {
|
||||
it('should add podmiot posredniczacy info when value is "1"', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
PodmiotPosredniczacy: { _text: '1' },
|
||||
} as any;
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Dostawa dokonana przez podmiot, o którym mowa w art. 22 ust. 2d ustawy'),
|
||||
[FormatTyp.Label, FormatTyp.MarginTop4]
|
||||
);
|
||||
});
|
||||
|
||||
it('should not add podmiot posredniczacy info when value is not "1"', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
PodmiotPosredniczacy: { _text: '0' },
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.formatText).mockClear();
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.formatText).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not add podmiot posredniczacy info when value is empty', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
PodmiotPosredniczacy: { _text: '' },
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.formatText).mockClear();
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.formatText).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('transport section', () => {
|
||||
it('should call generateTransport for each transport item', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
Transport: [{ RodzajTransportu: { _text: 'Road' } }, { RodzajTransportu: { _text: 'Air' } }],
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockImplementation((field: any) => {
|
||||
if (field === data.Transport) {
|
||||
return [{ RodzajTransportu: { _text: 'Road' } }, { RodzajTransportu: { _text: 'Air' } }] as any;
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
vi.mocked(TransportModule.generateTransport).mockReturnValue('transport' as any);
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(TransportModule.generateTransport).toHaveBeenCalledTimes(2);
|
||||
expect(TransportModule.generateTransport).toHaveBeenCalledWith(
|
||||
{
|
||||
RodzajTransportu: { _text: 'Road' },
|
||||
},
|
||||
1
|
||||
);
|
||||
expect(TransportModule.generateTransport).toHaveBeenCalledWith(
|
||||
{
|
||||
RodzajTransportu: { _text: 'Air' },
|
||||
},
|
||||
2
|
||||
);
|
||||
});
|
||||
|
||||
it('should not call generateTransport when Transport is undefined', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
Transport: undefined,
|
||||
} as any;
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(TransportModule.generateTransport).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not call generateTransport when Transport is empty', () => {
|
||||
const data = {
|
||||
...mockWarunkiTransakcji,
|
||||
Transport: [],
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([]);
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(TransportModule.generateTransport).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('complete integration', () => {
|
||||
it('should handle all sections when fully populated', () => {
|
||||
const data = {
|
||||
Umowy: [{ DataUmowy: { _text: '2024-01-01' }, NrUmowy: { _text: 'U001' } }],
|
||||
Zamowienia: [{ DataZamowienia: { _text: '2024-01-02' }, NrZamowienia: { _text: 'Z001' } }],
|
||||
NrPartiiTowaru: [{ _text: 'BATCH001' }],
|
||||
WalutaUmowna: { _text: 'EUR' },
|
||||
KursUmowny: { _text: '4.50' },
|
||||
WarunkiDostawy: { _text: 'FOB' },
|
||||
PodmiotPosredniczacy: { _text: '1' },
|
||||
Transport: [{ RodzajTransportu: { _text: 'Road' } }],
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockImplementation((field: any) => {
|
||||
if (field === data.Umowy) return [{ DataUmowy: { _text: '2024-01-01' } }] as any;
|
||||
if (field === data.Zamowienia) return [{ DataZamowienia: { _text: '2024-01-02' } }] as any;
|
||||
if (field === data.NrPartiiTowaru) return [{ _text: 'BATCH001' }] as any;
|
||||
if (field === data.Transport) return [{ RodzajTransportu: { _text: 'Road' } }] as any;
|
||||
return [];
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable)
|
||||
.mockReturnValueOnce({ content: { table: 'umowy' } as any, fieldsWithValue: ['DataUmowy'] })
|
||||
.mockReturnValueOnce({
|
||||
content: { table: 'zamowienia' } as any,
|
||||
fieldsWithValue: ['DataZamowienia'],
|
||||
})
|
||||
.mockReturnValueOnce({ content: { table: 'partia' } as any, fieldsWithValue: ['_text'] });
|
||||
|
||||
generateWarunkiTransakcji(data);
|
||||
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Warunki transakcji', [0, 8, 0, 4]);
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Waluta umowna i kurs umowny', [0, 8, 0, 4]);
|
||||
expect(PDFFunctions.createSubHeader).toHaveBeenCalledWith('Umowa');
|
||||
expect(PDFFunctions.createSubHeader).toHaveBeenCalledWith('Zamówienie');
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalled();
|
||||
expect(TransportModule.generateTransport).toHaveBeenCalled();
|
||||
expect(PDFFunctions.createSection).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
105
src/lib-public/generators/FA1/WarunkiTransakcji.ts
Normal file
105
src/lib-public/generators/FA1/WarunkiTransakcji.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
createSection,
|
||||
createSubHeader,
|
||||
formatText,
|
||||
generateTwoColumns,
|
||||
getContentTable,
|
||||
getTable,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { FP, Umowy, WarunkiTransakcji, Zamowienia } from '../../types/fa1.types';
|
||||
import { generateTransport } from './Transport';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { FormContentState } from '../../../shared/types/additional-data.types';
|
||||
|
||||
export function generateWarunkiTransakcji(warunkiTransakcji: WarunkiTransakcji | undefined): Content {
|
||||
if (!warunkiTransakcji) {
|
||||
return [];
|
||||
}
|
||||
const table: Content[] = [];
|
||||
const Kolumny = { umowy: [] as Content[], zamowienia: [] as Content[] };
|
||||
const umowy: Umowy[] = getTable(warunkiTransakcji?.Umowy);
|
||||
const zamowienia: Zamowienia[] = getTable(warunkiTransakcji?.Zamowienia);
|
||||
const partiaTowaru: FP[] = getTable(warunkiTransakcji?.NrPartiiTowaru);
|
||||
const definedHeaderUmowy: HeaderDefine[] = [
|
||||
{ name: 'DataUmowy', title: 'Data umowy', format: FormatTyp.Default },
|
||||
{ name: 'NrUmowy', title: 'Numer umowy', format: FormatTyp.Default },
|
||||
];
|
||||
const definedHeaderZamowienia: HeaderDefine[] = [
|
||||
{ name: 'DataZamowienia', title: 'Data zamówienia', format: FormatTyp.Default },
|
||||
{ name: 'NrZamowienia', title: 'Numer zamówienia', format: FormatTyp.Default },
|
||||
];
|
||||
const definedHeaderPartiaTowaru: HeaderDefine[] = [
|
||||
{ name: '', title: 'Numer partii towaru', format: FormatTyp.Default },
|
||||
];
|
||||
|
||||
table.push(createHeader('Warunki transakcji', [0, 8, 0, 4]));
|
||||
|
||||
if (umowy.length > 0) {
|
||||
const tabUmowy: FormContentState = getContentTable<(typeof umowy)[0]>(definedHeaderUmowy, umowy, '*');
|
||||
|
||||
if (tabUmowy.content) {
|
||||
Kolumny.umowy = [createSubHeader('Umowa'), tabUmowy.content];
|
||||
}
|
||||
}
|
||||
if (zamowienia.length > 0) {
|
||||
const tabZamowienia: FormContentState = getContentTable<(typeof zamowienia)[0]>(
|
||||
definedHeaderZamowienia,
|
||||
zamowienia,
|
||||
'*'
|
||||
);
|
||||
|
||||
if (tabZamowienia.content && tabZamowienia.fieldsWithValue.length > 0) {
|
||||
Kolumny.zamowienia = [createSubHeader('Zamówienie'), tabZamowienia.content];
|
||||
}
|
||||
}
|
||||
|
||||
if (Kolumny.zamowienia.length > 0 || Kolumny.umowy.length > 0) {
|
||||
table.push(generateTwoColumns(Kolumny.umowy, Kolumny.zamowienia));
|
||||
}
|
||||
if (warunkiTransakcji.WalutaUmowna?._text || warunkiTransakcji.KursUmowny?._text) {
|
||||
table.push(createHeader('Waluta umowna i kurs umowny', [0, 8, 0, 4]));
|
||||
|
||||
table.push(createLabelText('Waluta umowna: ', warunkiTransakcji.WalutaUmowna));
|
||||
table.push(createLabelText('Kurs umowny: ', warunkiTransakcji.KursUmowny));
|
||||
}
|
||||
|
||||
if (partiaTowaru.length > 0) {
|
||||
const tabPartiaTowaru: FormContentState = getContentTable<(typeof partiaTowaru)[0]>(
|
||||
definedHeaderPartiaTowaru,
|
||||
partiaTowaru,
|
||||
'*',
|
||||
[0, 4]
|
||||
);
|
||||
|
||||
if (tabPartiaTowaru.content) {
|
||||
table.push(generateTwoColumns(tabPartiaTowaru.content, ' '));
|
||||
}
|
||||
}
|
||||
|
||||
table.push(
|
||||
createLabelText('Warunki dostawy towarów: ', warunkiTransakcji.WarunkiDostawy, FormatTyp.MarginTop4)
|
||||
);
|
||||
|
||||
if (warunkiTransakcji.PodmiotPosredniczacy?._text === '1') {
|
||||
table.push(
|
||||
formatText(
|
||||
'Dostawa dokonana przez podmiot, o którym mowa w art. 22 ust. 2d ustawy. Pole dotyczy sytuacji, w której podmiot uczestniczy w transakcji łańcuchowej innej niż procedura trójstronna uproszczona, o której mowa w art. 135 ust. 1 pkt 4 ustawy',
|
||||
[FormatTyp.Label, FormatTyp.MarginTop4]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (warunkiTransakcji.Transport) {
|
||||
getTable(warunkiTransakcji.Transport).forEach((transport, index) => {
|
||||
table.push(
|
||||
generateTransport(transport, getTable(warunkiTransakcji.Transport).length !== 0 ? index + 1 : null)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return createSection(table, true);
|
||||
}
|
||||
379
src/lib-public/generators/FA1/Wiersze.spec.ts
Normal file
379
src/lib-public/generators/FA1/Wiersze.spec.ts
Normal file
@@ -0,0 +1,379 @@
|
||||
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 { Fa } from '../../types/fa1.types';
|
||||
import { generateWiersze } from './Wiersze';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn(),
|
||||
createLabelTextArray: vi.fn(),
|
||||
createSection: vi.fn(),
|
||||
formatText: vi.fn(),
|
||||
getContentTable: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
getValue: vi.fn(),
|
||||
}));
|
||||
|
||||
describe(generateWiersze.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
const mockFaVat: Fa = {
|
||||
FaWiersz: [
|
||||
{
|
||||
NrWierszaFa: { _text: '1' },
|
||||
P_7: { _text: 'Product 1' },
|
||||
P_9A: { _text: '100' },
|
||||
P_8B: { _text: '2' },
|
||||
},
|
||||
],
|
||||
KodWaluty: { _text: 'PLN' },
|
||||
P_15: { _text: '200' },
|
||||
RodzajFaktury: { _text: TRodzajFaktury.VAT },
|
||||
} as any;
|
||||
|
||||
const setupBasicMocks = (p15Value: string, rodzajFakturyValue: string, currencyValue: string = 'PLN') => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([
|
||||
{
|
||||
NrWierszaFa: { _text: '1' },
|
||||
P_7: { _text: 'Product 1' },
|
||||
P_9A: { _text: '100' },
|
||||
},
|
||||
] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['P_11', 'P_7'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getValue).mockImplementation((field: any) => {
|
||||
if (field === mockFaVat.P_15 || field?._text === p15Value) return p15Value;
|
||||
if (field === mockFaVat.RodzajFaktury || field?._text === rodzajFakturyValue) return rodzajFakturyValue;
|
||||
if (field === mockFaVat.KodWaluty || field?._text === currencyValue) return currencyValue;
|
||||
return undefined;
|
||||
});
|
||||
|
||||
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.createLabelTextArray).mockReturnValue(['Label', 'Value'] as any);
|
||||
};
|
||||
|
||||
describe('when no invoice lines exist', () => {
|
||||
it('should return empty array when table is empty', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([]);
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: null,
|
||||
fieldsWithValue: [],
|
||||
});
|
||||
vi.mocked(PDFFunctions.getValue).mockReturnValue('0');
|
||||
|
||||
const result = generateWiersze(mockFaVat);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when invoice lines exist', () => {
|
||||
it('should call getTable with FaWiersz', () => {
|
||||
setupBasicMocks('200', TRodzajFaktury.VAT);
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.getTable).toHaveBeenCalledWith(mockFaVat.FaWiersze);
|
||||
});
|
||||
|
||||
it('should call createHeader with "Pozycje"', () => {
|
||||
setupBasicMocks('200', TRodzajFaktury.VAT);
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith('Pozycje');
|
||||
});
|
||||
|
||||
describe('price text formatting', () => {
|
||||
it('should display "netto" when P_11 is in fieldsWithValue', () => {
|
||||
setupBasicMocks('200', TRodzajFaktury.VAT);
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(expect.stringContaining('netto'), [
|
||||
FormatTyp.Label,
|
||||
FormatTyp.MarginBottom8,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should display "brutto" when P_11 is not in fieldsWithValue', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['P_11A', 'P_7'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getValue).mockReturnValue('0');
|
||||
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);
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(expect.stringContaining('brutto'), [
|
||||
FormatTyp.Label,
|
||||
FormatTyp.MarginBottom8,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should include currency code in price text', () => {
|
||||
setupBasicMocks('200', TRodzajFaktury.VAT);
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith(expect.stringContaining('PLN'), [
|
||||
FormatTyp.Label,
|
||||
FormatTyp.MarginBottom8,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('table generation', () => {
|
||||
it('should generate single table when fieldsWithValue.length <= 8', () => {
|
||||
setupBasicMocks('200', TRodzajFaktury.VAT);
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should generate two tables when fieldsWithValue.length > 8', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable)
|
||||
.mockReturnValueOnce({
|
||||
content: null,
|
||||
fieldsWithValue: Array(9).fill('field'),
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
content: { table: 'table1' } as any,
|
||||
fieldsWithValue: ['field1', 'field2'],
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
content: { table: 'table2' } as any,
|
||||
fieldsWithValue: ['field3', 'field4'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getValue).mockReturnValue('0');
|
||||
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);
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
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.getContentTable)
|
||||
.mockReturnValueOnce({
|
||||
content: null,
|
||||
fieldsWithValue: Array(9).fill('field'),
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
content: { table: 'table1' } as any,
|
||||
fieldsWithValue: ['field1', 'field2'],
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
content: { table: 'table2' } as any,
|
||||
fieldsWithValue: ['field1'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getValue).mockReturnValue('0');
|
||||
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);
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
const sectionCall = vi.mocked(PDFFunctions.createSection).mock.calls[0][0];
|
||||
expect(sectionCall).not.toContain('\n');
|
||||
expect(sectionCall.filter((item: any) => item?.table === 'table2')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('payment amount description', () => {
|
||||
it('should add "Kwota pozostała do zapłaty" for ROZ invoice type when P_15 > 0', () => {
|
||||
setupBasicMocks('150', TRodzajFaktury.ROZ, 'EUR');
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).toHaveBeenCalledWith([
|
||||
{ value: 'Kwota pozostała do zapłaty: ', formatTyp: FormatTyp.LabelGreater },
|
||||
{
|
||||
value: '150',
|
||||
formatTyp: FormatTyp.CurrencyGreater,
|
||||
currency: 'EUR',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not add description for ROZ invoice when P_15 = 0', () => {
|
||||
setupBasicMocks('0', TRodzajFaktury.ROZ, 'EUR');
|
||||
vi.mocked(PDFFunctions.createLabelTextArray).mockClear();
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add "Kwota należności ogółem" for VAT invoice when P_15 > 0', () => {
|
||||
setupBasicMocks('200', TRodzajFaktury.VAT, 'PLN');
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).toHaveBeenCalledWith([
|
||||
{ value: 'Kwota należności ogółem: ', formatTyp: FormatTyp.LabelGreater },
|
||||
{
|
||||
value: '200',
|
||||
formatTyp: [FormatTyp.CurrencyGreater],
|
||||
currency: 'PLN',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should add description for KOR invoice when P_15 > 0', () => {
|
||||
setupBasicMocks('300', TRodzajFaktury.KOR, 'USD');
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).toHaveBeenCalledWith([
|
||||
{ value: 'Kwota należności ogółem: ', formatTyp: FormatTyp.LabelGreater },
|
||||
{
|
||||
value: '300',
|
||||
formatTyp: [FormatTyp.CurrencyGreater],
|
||||
currency: 'USD',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should add description for KOR_ROZ invoice when P_15 > 0', () => {
|
||||
setupBasicMocks('250', TRodzajFaktury.KOR_ROZ, 'PLN');
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add description for UPR invoice when P_15 > 0', () => {
|
||||
setupBasicMocks('180', TRodzajFaktury.UPR, 'PLN');
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not add description for VAT invoice when P_15 = 0', () => {
|
||||
setupBasicMocks('0', TRodzajFaktury.VAT, 'PLN');
|
||||
vi.mocked(PDFFunctions.createLabelTextArray).mockClear();
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should use empty string for currency if KodWaluty is undefined', () => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([{ NrWierszaFa: { _text: '1' } }] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['P_11', 'P_7'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.getValue).mockImplementation((field: any) => {
|
||||
if (field === mockFaVat.P_15) return '200';
|
||||
if (field === mockFaVat.RodzajFaktury) return TRodzajFaktury.VAT;
|
||||
if (field === mockFaVat.KodWaluty) return undefined;
|
||||
return undefined;
|
||||
});
|
||||
|
||||
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.createLabelTextArray).mockReturnValue(['Label', 'Value'] as any);
|
||||
|
||||
const faVatNoCurrency = { ...mockFaVat, KodWaluty: undefined } as any;
|
||||
|
||||
generateWiersze(faVatNoCurrency);
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
currency: '',
|
||||
}),
|
||||
])
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createSection call', () => {
|
||||
it('should call createSection with correct parameters', () => {
|
||||
setupBasicMocks('200', TRodzajFaktury.VAT);
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
expect(PDFFunctions.createSection).toHaveBeenCalledWith(
|
||||
expect.arrayContaining(['Header', 'formatted text']),
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should return the result of createSection', () => {
|
||||
const mockSection = { section: 'test' };
|
||||
setupBasicMocks('200', TRodzajFaktury.VAT);
|
||||
vi.mocked(PDFFunctions.createSection).mockReturnValue(mockSection as any);
|
||||
|
||||
const result = generateWiersze(mockFaVat);
|
||||
|
||||
expect(result).toEqual(mockSection);
|
||||
});
|
||||
});
|
||||
|
||||
describe('header definitions', () => {
|
||||
it('should include all required headers in first table', () => {
|
||||
setupBasicMocks('200', TRodzajFaktury.VAT);
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
const firstCall = vi.mocked(PDFFunctions.getContentTable).mock.calls[0];
|
||||
const headers = firstCall[0];
|
||||
|
||||
expect(headers).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ name: 'NrWierszaFa', title: 'Lp.' }),
|
||||
expect.objectContaining({ name: 'P_7', title: 'Nazwa towaru lub usługi' }),
|
||||
expect.objectContaining({ name: 'P_9A', title: 'Cena jedn. netto' }),
|
||||
expect.objectContaining({ name: 'P_11', title: 'Wartość sprzedaży netto' }),
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it('should use correct format types for currency fields', () => {
|
||||
setupBasicMocks('200', TRodzajFaktury.VAT);
|
||||
|
||||
generateWiersze(mockFaVat);
|
||||
|
||||
const firstCall = vi.mocked(PDFFunctions.getContentTable).mock.calls[0];
|
||||
const headers = firstCall[0];
|
||||
|
||||
const currencyHeaders = headers.filter(
|
||||
(h: any) => h.format === FormatTyp.Currency || h.format === FormatTyp.Currency6
|
||||
);
|
||||
|
||||
expect(currencyHeaders.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
130
src/lib-public/generators/FA1/Wiersze.ts
Normal file
130
src/lib-public/generators/FA1/Wiersze.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { Content, ContentStack, ContentText } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelTextArray,
|
||||
createSection,
|
||||
formatText,
|
||||
getContentTable,
|
||||
getTable,
|
||||
getValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
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';
|
||||
|
||||
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 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 definedHeaderLp: HeaderDefine[] = [
|
||||
{ name: 'NrWierszaFa', title: 'Lp.', format: FormatTyp.Default, width: 'auto' },
|
||||
];
|
||||
const definedHeader1: HeaderDefine[] = [
|
||||
{ name: 'UU_ID', title: 'Unikalny numer wiersza', format: FormatTyp.Default, width: 'auto' },
|
||||
{ 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_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' },
|
||||
{ name: 'P_12_XII', title: 'Stawka podatku OSS', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'P_11', title: 'Wartość sprzedaży netto', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'P_11A', title: 'Wartość sprzedaży brutto', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'KursWaluty', title: 'Kurs waluty', format: FormatTyp.Currency6, width: 'auto' },
|
||||
];
|
||||
const definedHeader2: HeaderDefine[] = [
|
||||
{ name: 'GTIN', title: 'GTIN', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'PKWiU', title: 'PKWiU', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'CN', title: 'CN', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'PKOB', title: 'PKOB', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'DodatkoweInfo', title: 'Dodatkowe informacje', format: FormatTyp.Default, width: 'auto' },
|
||||
{
|
||||
name: 'P_12_Procedura',
|
||||
title: 'Procedura',
|
||||
format: FormatTyp.Default,
|
||||
mappingData: Procedura,
|
||||
width: '*',
|
||||
},
|
||||
{ name: 'KwotaAkcyzy', title: 'KwotaAkcyzy', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'GTU', title: 'GTU', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'Procedura', title: 'Oznaczenia dotyczące procedur', format: FormatTyp.Default, width: '*' },
|
||||
{ name: 'P_6A', title: 'Data dostawy / wykonania', format: FormatTyp.Default, width: 'auto' },
|
||||
];
|
||||
let content: FormContentState = getContentTable<(typeof faWiersze)[0]>(
|
||||
[...definedHeaderLp, ...definedHeader1, ...definedHeader2],
|
||||
faWiersze,
|
||||
'*'
|
||||
);
|
||||
const ceny: string | ContentText = formatText(
|
||||
`Faktura wystawiona w cenach ${content.fieldsWithValue.includes('P_11') ? 'netto' : 'brutto'} w walucie ${faVat.KodWaluty?._text}`,
|
||||
[FormatTyp.Label, FormatTyp.MarginBottom8]
|
||||
);
|
||||
|
||||
const p_15: string | number | undefined = getValue(faVat.P_15);
|
||||
let opis: ContentStack[] = [];
|
||||
|
||||
if (rodzajFaktury == TRodzajFaktury.ROZ && Number(p_15) !== 0) {
|
||||
opis = [
|
||||
{
|
||||
stack: createLabelTextArray([
|
||||
{ value: 'Kwota pozostała do zapłaty: ', formatTyp: FormatTyp.LabelGreater },
|
||||
{
|
||||
value: p_15,
|
||||
formatTyp: FormatTyp.CurrencyGreater,
|
||||
currency: getValue(faVat.KodWaluty)?.toString() ?? '',
|
||||
},
|
||||
]),
|
||||
alignment: Position.RIGHT,
|
||||
margin: [0, 8, 0, 0],
|
||||
},
|
||||
];
|
||||
} else if (
|
||||
(rodzajFaktury == TRodzajFaktury.VAT ||
|
||||
rodzajFaktury == TRodzajFaktury.KOR ||
|
||||
rodzajFaktury == TRodzajFaktury.KOR_ROZ ||
|
||||
rodzajFaktury == TRodzajFaktury.UPR) &&
|
||||
Number(p_15) !== 0
|
||||
) {
|
||||
opis = [
|
||||
{
|
||||
stack: createLabelTextArray([
|
||||
{ value: 'Kwota należności ogółem: ', formatTyp: FormatTyp.LabelGreater },
|
||||
{
|
||||
value: p_15,
|
||||
formatTyp: [FormatTyp.CurrencyGreater],
|
||||
currency: getValue(faVat.KodWaluty)?.toString() ?? '',
|
||||
},
|
||||
]),
|
||||
alignment: Position.RIGHT,
|
||||
margin: [0, 8, 0, 0],
|
||||
},
|
||||
];
|
||||
}
|
||||
if (content.fieldsWithValue.length <= 9 && content.content) {
|
||||
table.push(content.content);
|
||||
} else {
|
||||
content = getContentTable<(typeof faWiersze)[0]>([...definedHeaderLp, ...definedHeader1], faWiersze, '*');
|
||||
if (content.content) {
|
||||
table.push(content.content);
|
||||
}
|
||||
content = getContentTable<(typeof faWiersze)[0]>([...definedHeaderLp, ...definedHeader2], faWiersze, '*');
|
||||
if (content.content && content.fieldsWithValue.length > 1) {
|
||||
table.push('\n');
|
||||
table.push(content.content);
|
||||
}
|
||||
}
|
||||
if (table.length < 1) {
|
||||
return [];
|
||||
}
|
||||
return createSection([...createHeader('Pozycje'), ceny, ...table, ...opis], true);
|
||||
}
|
||||
288
src/lib-public/generators/FA1/Zamowienia.spec.ts
Normal file
288
src/lib-public/generators/FA1/Zamowienia.spec.ts
Normal file
@@ -0,0 +1,288 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import * as PDFFunctions from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { TRodzajFaktury } from '../../../shared/consts/const';
|
||||
import { Zamowienie } from '../../types/fa1.types';
|
||||
import { generateZamowienie } from './Zamowienie';
|
||||
import { ZamowienieKorekta } from '../../enums/invoice.enums';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn(),
|
||||
createLabelTextArray: vi.fn(),
|
||||
formatText: vi.fn(),
|
||||
getContentTable: vi.fn(),
|
||||
getTable: vi.fn(),
|
||||
}));
|
||||
|
||||
describe(generateZamowienie.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('when orderData is undefined', () => {
|
||||
it('should return an empty array', () => {
|
||||
const result = generateZamowienie(
|
||||
undefined,
|
||||
ZamowienieKorekta.BeforeCorrection,
|
||||
'100',
|
||||
TRodzajFaktury.ZAL,
|
||||
'PLN'
|
||||
);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when orderData is defined', () => {
|
||||
const mockOrderData: Zamowienie = {
|
||||
ZamowienieWiersz: [
|
||||
{
|
||||
NrWierszaZam: { _text: '1' },
|
||||
P_7Z: { _text: 'Towar 1' },
|
||||
P_9AZ: { _text: '100' },
|
||||
P_8BZ: { _text: '2' },
|
||||
},
|
||||
],
|
||||
WartoscZamowienia: { _text: '200' },
|
||||
} as any;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([
|
||||
{
|
||||
NrWierszaZam: { _text: '1' },
|
||||
P_7Z: { _text: 'Towar 1' },
|
||||
P_9AZ: { _text: '100' },
|
||||
P_8BZ: { _text: '2' },
|
||||
},
|
||||
] as any);
|
||||
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['P_11'],
|
||||
});
|
||||
|
||||
vi.mocked(PDFFunctions.createHeader).mockReturnValue('Header' as any);
|
||||
vi.mocked(PDFFunctions.formatText).mockReturnValue('200 PLN' as any);
|
||||
});
|
||||
|
||||
it('should call getTable with ZamowienieWiersz', () => {
|
||||
generateZamowienie(mockOrderData, ZamowienieKorekta.BeforeCorrection, '100', TRodzajFaktury.ZAL, 'PLN');
|
||||
|
||||
expect(PDFFunctions.getTable).toHaveBeenCalledWith(mockOrderData.ZamowienieWiersz);
|
||||
});
|
||||
|
||||
it('should fill NrWierszaZam if it is empty', () => {
|
||||
const dataWithEmptyNr = {
|
||||
...mockOrderData,
|
||||
ZamowienieWiersz: [
|
||||
{
|
||||
NrWierszaZam: { _text: '' },
|
||||
P_7Z: { _text: 'Towar 1' },
|
||||
},
|
||||
],
|
||||
} as any;
|
||||
|
||||
vi.mocked(PDFFunctions.getTable).mockReturnValue([
|
||||
{
|
||||
NrWierszaZam: { _text: '' },
|
||||
P_7Z: { _text: 'Towar 1' },
|
||||
},
|
||||
] as any);
|
||||
|
||||
generateZamowienie(
|
||||
dataWithEmptyNr,
|
||||
ZamowienieKorekta.BeforeCorrection,
|
||||
'100',
|
||||
TRodzajFaktury.ZAL,
|
||||
'PLN'
|
||||
);
|
||||
|
||||
const tableCall = vi.mocked(PDFFunctions.getTable).mock.results[0].value;
|
||||
expect(tableCall[0].NrWierszaZam._text).toBe('1');
|
||||
});
|
||||
|
||||
describe('price formatting', () => {
|
||||
it('should use FormatTyp.CurrencyAbs for BeforeCorrection', () => {
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['field1', 'field2', 'field3'],
|
||||
});
|
||||
|
||||
generateZamowienie(
|
||||
mockOrderData,
|
||||
ZamowienieKorekta.BeforeCorrection,
|
||||
'100',
|
||||
TRodzajFaktury.ZAL,
|
||||
'PLN'
|
||||
);
|
||||
|
||||
const calls = vi.mocked(PDFFunctions.getContentTable).mock.calls;
|
||||
const header = calls[0][0];
|
||||
const cenaNetto = header.find((h: any) => h.name === 'P_9AZ');
|
||||
expect(cenaNetto?.format).toBe(FormatTyp.CurrencyAbs);
|
||||
});
|
||||
|
||||
it('should use FormatTyp.Currency when not BeforeCorrection', () => {
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['field1', 'field2', 'field3'],
|
||||
});
|
||||
|
||||
generateZamowienie(
|
||||
mockOrderData,
|
||||
ZamowienieKorekta.AfterCorrection,
|
||||
'100',
|
||||
TRodzajFaktury.KOR_ZAL,
|
||||
'PLN'
|
||||
);
|
||||
|
||||
const calls = vi.mocked(PDFFunctions.getContentTable).mock.calls;
|
||||
const header = calls[0][0];
|
||||
const cenaNetto = header.find((h: any) => h.name === 'P_9AZ');
|
||||
expect(cenaNetto?.format).toBe(FormatTyp.Currency);
|
||||
});
|
||||
});
|
||||
|
||||
describe('table generation', () => {
|
||||
it('should generate one table when fieldsWithValue.length <= 8', () => {
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['field1', 'field2', 'field3'],
|
||||
});
|
||||
|
||||
const result = generateZamowienie(
|
||||
mockOrderData,
|
||||
ZamowienieKorekta.BeforeCorrection,
|
||||
'100',
|
||||
TRodzajFaktury.ZAL,
|
||||
'PLN'
|
||||
);
|
||||
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledTimes(1);
|
||||
expect(result[0]).toBeDefined();
|
||||
});
|
||||
|
||||
it('should generate two tables when fieldsWithValue.length > 8', () => {
|
||||
vi.mocked(PDFFunctions.getContentTable)
|
||||
.mockReturnValueOnce({
|
||||
content: null,
|
||||
fieldsWithValue: Array(9).fill('field'),
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['field1', 'field2'],
|
||||
})
|
||||
.mockReturnValueOnce({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['field3', 'field4'],
|
||||
});
|
||||
|
||||
generateZamowienie(
|
||||
mockOrderData,
|
||||
ZamowienieKorekta.BeforeCorrection,
|
||||
'100',
|
||||
TRodzajFaktury.ZAL,
|
||||
'PLN'
|
||||
);
|
||||
|
||||
expect(PDFFunctions.getContentTable).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('payment amount description', () => {
|
||||
it('should add description for advance invoice (ZAL) when p_15 > 0', () => {
|
||||
vi.mocked(PDFFunctions.createLabelTextArray).mockReturnValue(['Label', 'Value'] as any);
|
||||
|
||||
const result = generateZamowienie(
|
||||
mockOrderData,
|
||||
ZamowienieKorekta.BeforeCorrection,
|
||||
'100',
|
||||
TRodzajFaktury.ZAL,
|
||||
'PLN'
|
||||
);
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).toHaveBeenCalledWith([
|
||||
{ value: 'Otrzymana kwota zapłaty (zaliczki): ', formatTyp: FormatTyp.LabelGreater },
|
||||
{ value: '100', formatTyp: FormatTyp.CurrencyGreater },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not add description for ZAL invoice when p_15 = 0', () => {
|
||||
vi.mocked(PDFFunctions.createLabelTextArray).mockClear();
|
||||
|
||||
generateZamowienie(mockOrderData, ZamowienieKorekta.BeforeCorrection, '0', TRodzajFaktury.ZAL, 'PLN');
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add description for advance correction (KOR_ZAL) when not BeforeCorrection', () => {
|
||||
vi.mocked(PDFFunctions.createLabelTextArray).mockReturnValue(['Label', 'Value'] as any);
|
||||
|
||||
generateZamowienie(
|
||||
mockOrderData,
|
||||
ZamowienieKorekta.AfterCorrection,
|
||||
'150',
|
||||
TRodzajFaktury.KOR_ZAL,
|
||||
'PLN'
|
||||
);
|
||||
|
||||
expect(PDFFunctions.createLabelTextArray).toHaveBeenCalledWith([
|
||||
{ value: 'Kwota należności ogółem: ', formatTyp: FormatTyp.LabelGreater },
|
||||
{ value: '150', formatTyp: FormatTyp.CurrencyGreater },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('price text', () => {
|
||||
it('should display "netto" when P_11 is in fieldsWithValue', () => {
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['P_11', 'P_7Z'],
|
||||
});
|
||||
|
||||
const result = generateZamowienie(
|
||||
mockOrderData,
|
||||
ZamowienieKorekta.BeforeCorrection,
|
||||
'100',
|
||||
TRodzajFaktury.ZAL,
|
||||
'EUR'
|
||||
);
|
||||
|
||||
const stack = (result[0] as any).stack;
|
||||
expect(stack[1]).toContain('netto');
|
||||
expect(stack[1]).toContain('EUR');
|
||||
});
|
||||
|
||||
it('should display "brutto" when P_11 is not in fieldsWithValue', () => {
|
||||
vi.mocked(PDFFunctions.getContentTable).mockReturnValue({
|
||||
content: { table: {} } as any,
|
||||
fieldsWithValue: ['P_7Z', 'P_9AZ'],
|
||||
});
|
||||
|
||||
const result = generateZamowienie(
|
||||
mockOrderData,
|
||||
ZamowienieKorekta.BeforeCorrection,
|
||||
'100',
|
||||
TRodzajFaktury.ZAL,
|
||||
'USD'
|
||||
);
|
||||
|
||||
const stack = (result[0] as any).stack;
|
||||
expect(stack[1]).toContain('brutto');
|
||||
expect(stack[1]).toContain('USD');
|
||||
});
|
||||
});
|
||||
|
||||
it('should call createHeader with correct parameter', () => {
|
||||
generateZamowienie(mockOrderData, ZamowienieKorekta.BeforeCorrection, '100', TRodzajFaktury.ZAL, 'PLN');
|
||||
|
||||
expect(PDFFunctions.createHeader).toHaveBeenCalledWith(ZamowienieKorekta.BeforeCorrection);
|
||||
});
|
||||
|
||||
it('should format order value', () => {
|
||||
generateZamowienie(mockOrderData, ZamowienieKorekta.BeforeCorrection, '100', TRodzajFaktury.ZAL, 'PLN');
|
||||
|
||||
expect(PDFFunctions.formatText).toHaveBeenCalledWith('200', FormatTyp.Currency);
|
||||
});
|
||||
});
|
||||
});
|
||||
143
src/lib-public/generators/FA1/Zamowienie.ts
Normal file
143
src/lib-public/generators/FA1/Zamowienie.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelTextArray,
|
||||
formatText,
|
||||
getContentTable,
|
||||
getTable,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { Procedura, TRodzajFaktury } from '../../../shared/consts/const';
|
||||
import { FP, Zamowienie } from '../../types/fa1.types';
|
||||
import FormatTyp, { Position } from '../../../shared/enums/common.enum';
|
||||
import { ZamowienieKorekta } from '../../enums/invoice.enums';
|
||||
import { FormContentState } from '../../../shared/types/additional-data.types';
|
||||
|
||||
export function generateZamowienie(
|
||||
orderData: Zamowienie | undefined,
|
||||
zamowienieKorekta: ZamowienieKorekta,
|
||||
p_15: string,
|
||||
rodzajFaktury: string,
|
||||
KodWaluty: string
|
||||
): Content[] {
|
||||
if (!orderData) {
|
||||
return [];
|
||||
}
|
||||
const formatAbs: FormatTyp.Currency | FormatTyp.CurrencyAbs =
|
||||
zamowienieKorekta === ZamowienieKorekta.BeforeCorrection ? FormatTyp.CurrencyAbs : FormatTyp.Currency;
|
||||
const orderTable: Record<string, FP>[] = getTable(orderData?.ZamowienieWiersz).map((el, index) => {
|
||||
if (!el.NrWierszaZam._text) {
|
||||
el.NrWierszaZam._text = (index + 1).toString();
|
||||
}
|
||||
return el;
|
||||
});
|
||||
const definedHeaderLp: HeaderDefine[] = [
|
||||
{ name: 'NrWierszaZam', title: 'Lp.', format: FormatTyp.Default, width: 'auto' },
|
||||
];
|
||||
const definedHeader1: HeaderDefine[] = [
|
||||
{ name: 'UU_IDZ', title: 'Unikalny numer wiersza', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'P_7Z', title: 'Nazwa towaru lub usługi', format: FormatTyp.Default, width: '*' },
|
||||
{
|
||||
name: 'P_9AZ',
|
||||
title: 'Cena jedn. netto',
|
||||
format: formatAbs,
|
||||
},
|
||||
{ name: 'P_8BZ', title: 'Ilość', format: FormatTyp.Right, width: 'auto' },
|
||||
{ name: 'P_8AZ', title: 'Miara', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'P_12Z', title: 'Stawka podatku', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'P_12Z_XII', title: 'Stawka podatku OSS', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'P_11NettoZ', title: 'Wartość sprzedaży netto', format: formatAbs, width: 'auto' },
|
||||
{ name: 'P_11VatZ', title: 'Kwota podatku', format: formatAbs, width: 'auto' },
|
||||
{ name: 'KursWalutyZ', title: 'Kwota podatku', format: formatAbs, width: 'auto' },
|
||||
];
|
||||
const definedHeader2: HeaderDefine[] = [
|
||||
{ name: 'GTINZ', title: 'GTIN', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'PKWiUZ', title: 'PKWiU', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'CNZ', title: 'CN', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'PKOBZ', title: 'PKOB', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'DodatkoweInfoZ', title: 'Dodatkowe informacje', format: FormatTyp.Default, width: '*' },
|
||||
{
|
||||
name: 'P_12Z_Procedura',
|
||||
title: 'Procedura',
|
||||
format: FormatTyp.Default,
|
||||
mappingData: Procedura,
|
||||
width: '*',
|
||||
},
|
||||
{ name: 'KwotaAkcyzyZ', title: 'Kwota podatku akcyzowego', format: FormatTyp.Currency, width: 'auto' },
|
||||
{ name: 'GTUZ', title: 'GTU', format: FormatTyp.Default, width: 'auto' },
|
||||
{ name: 'ProceduraZ', title: 'Oznaczenia dotyczące procedur', format: FormatTyp.Default, width: '*' },
|
||||
];
|
||||
|
||||
let content: FormContentState = getContentTable<(typeof orderTable)[0]>(
|
||||
[...definedHeaderLp, ...definedHeader1, ...definedHeader2],
|
||||
orderTable,
|
||||
'*'
|
||||
);
|
||||
const table: Content[] = [];
|
||||
|
||||
if (content.fieldsWithValue.length <= 9) {
|
||||
if (content.content) {
|
||||
table.push(content.content);
|
||||
}
|
||||
} else {
|
||||
content = getContentTable<(typeof orderTable)[0]>(
|
||||
[...definedHeaderLp, ...definedHeader1],
|
||||
orderTable,
|
||||
'*'
|
||||
);
|
||||
if (content.content) {
|
||||
table.push(content.content);
|
||||
}
|
||||
content = getContentTable<(typeof orderTable)[0]>(
|
||||
[...definedHeaderLp, ...definedHeader2],
|
||||
orderTable,
|
||||
'*'
|
||||
);
|
||||
if (content.content && content.fieldsWithValue.length > 1) {
|
||||
table.push(content.content);
|
||||
}
|
||||
}
|
||||
const ceny = `Faktura wystawiona w cenach ${content.fieldsWithValue.includes('P_11') ? 'netto' : 'brutto'} w walucie ${KodWaluty}`;
|
||||
let opis: Content = '';
|
||||
|
||||
if (Number(p_15) > 0 && rodzajFaktury == TRodzajFaktury.ZAL) {
|
||||
opis = {
|
||||
stack: createLabelTextArray([
|
||||
{ value: 'Otrzymana kwota zapłaty (zaliczki): ', formatTyp: FormatTyp.LabelGreater },
|
||||
{ value: p_15, formatTyp: FormatTyp.CurrencyGreater },
|
||||
]),
|
||||
alignment: Position.RIGHT,
|
||||
margin: [0, 8, 0, 0],
|
||||
};
|
||||
} else if (
|
||||
zamowienieKorekta !== ZamowienieKorekta.BeforeCorrection &&
|
||||
rodzajFaktury == TRodzajFaktury.KOR_ZAL &&
|
||||
Number(p_15) >= 0
|
||||
) {
|
||||
opis = {
|
||||
stack: createLabelTextArray([
|
||||
{ value: 'Kwota należności ogółem: ', formatTyp: FormatTyp.LabelGreater },
|
||||
{ value: p_15, formatTyp: FormatTyp.CurrencyGreater },
|
||||
]),
|
||||
alignment: Position.RIGHT,
|
||||
margin: [0, 8, 0, 0],
|
||||
};
|
||||
}
|
||||
return [
|
||||
{
|
||||
stack: [
|
||||
createHeader(zamowienieKorekta),
|
||||
ceny,
|
||||
{
|
||||
text: [
|
||||
'Wartość zamówienia lub umowy z uwzględnieniem kwoty podatku: ',
|
||||
formatText(orderData.WartoscZamowienia?._text, FormatTyp.Currency),
|
||||
],
|
||||
marginBottom: 4,
|
||||
},
|
||||
...table,
|
||||
opis,
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
179
src/lib-public/generators/FA2/Adnotacje.spec.ts
Normal file
179
src/lib-public/generators/FA2/Adnotacje.spec.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
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' })),
|
||||
createLabelText: vi.fn((label: string, value: string) => [{ text: label + value }]),
|
||||
formatText: vi.fn((text: string) => ({ text })),
|
||||
getTable: vi.fn(() => []),
|
||||
hasValue: vi.fn((v) => !!v?._text),
|
||||
verticalSpacing: vi.fn((n: number) => ({ text: `space-${n}` })),
|
||||
}));
|
||||
|
||||
describe(generateAdnotacje.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('zwraca pustą tablicę jeśli brak adnotacji', () => {
|
||||
const result = generateAdnotacje(undefined);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
test.each([
|
||||
[{ Zwolnienie: { P_19: { _text: '1' } } }, true, 'powinien dodać nagłówek i sekcję "Adnotacje"'],
|
||||
[{ P_18A: { _text: '1' } }, true, 'powinien dodać "Mechanizm podzielonej płatności"'],
|
||||
[{ P_16: { _text: '1' } }, true, 'powinien dodać "Metoda kasowa"'],
|
||||
[{ P_18: { _text: '1' } }, true, 'powinien dodać "Odwrotne obciążenie"'],
|
||||
[{ P_23: { _text: '1' } }, true, 'powinien dodać "Procedura trójstronna uproszczona"'],
|
||||
[{ P_17: { _text: '1' } }, true, 'powinien dodać "Samofakturowanie"'],
|
||||
])('dla adnotacji %s %s (%s)', (adnotacje, expected, desc) => {
|
||||
const result = generateAdnotacje(adnotacje as any);
|
||||
|
||||
if (expected) {
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
expect(createHeader).toHaveBeenCalledWith('Adnotacje');
|
||||
} else {
|
||||
expect(result).toEqual([]);
|
||||
}
|
||||
});
|
||||
|
||||
it('dodaje adnotacje dla NoweSrodkiTransportu z VAT-22', () => {
|
||||
const adnotacje = {
|
||||
NoweSrodkiTransportu: { P_42_5: { _text: '1' } },
|
||||
};
|
||||
const result = generateAdnotacje(adnotacje as any);
|
||||
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('dodaje procedurę marży', () => {
|
||||
const adnotacje = {
|
||||
PMarzy: { P_PMarzy: { _text: '1' }, P_PMarzy_3_1: { _text: '1' } },
|
||||
};
|
||||
const result = generateAdnotacje(adnotacje as any);
|
||||
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
expect(createLabelText).toHaveBeenCalledWith('Procedura marży: ', 'towary używane');
|
||||
});
|
||||
});
|
||||
|
||||
describe(generateDostawy.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('zwraca pustą tablicę jeśli brak danych', () => {
|
||||
(getTable as any).mockReturnValueOnce([]);
|
||||
const result = generateDostawy({} as any);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('generuje tabelę jeśli są dane', () => {
|
||||
(getTable as any).mockReturnValueOnce([
|
||||
{
|
||||
P_22A: { _text: '2025-01-01' },
|
||||
P_22B: { _text: '123' },
|
||||
DetailsString: { _text: 'Test opis' },
|
||||
},
|
||||
]);
|
||||
|
||||
const result = generateDostawy({ NowySrodekTransportu: [] } as any);
|
||||
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
expect(result[0]).toHaveProperty('table');
|
||||
expect(formatText).toHaveBeenCalledWith('2025-01-01');
|
||||
});
|
||||
|
||||
test.each([
|
||||
['P_22B', 'Dostawa dotyczy pojazdów lądowych, o których mowa w art. 2 pkt 10 lit. a ustawy'],
|
||||
['P_22C', 'Dostawa dotyczy jednostek pływających, o których mowa w art. 2 pkt 10 lit. b ustawy'],
|
||||
['P_22D', 'Dostawa dotyczy statków powietrznych, o których mowa w art. 2 pkt 10 lit. c ustawy'],
|
||||
])('poprawnie rozpoznaje typ środka transportu (%s)', (field, expected) => {
|
||||
(getTable as any).mockReturnValueOnce([{ [field]: { _text: '1' } }]);
|
||||
|
||||
const result = generateDostawy({ NowySrodekTransportu: [] } as any);
|
||||
const textOutput = JSON.stringify(result);
|
||||
|
||||
expect(textOutput).toContain(expected);
|
||||
});
|
||||
|
||||
it('adds all Zwolnienie fields together (P_19A, P_19B, P_19C)', () => {
|
||||
const annotations = {
|
||||
Zwolnienie: {
|
||||
P_19: { _text: '1' },
|
||||
P_19A: { _text: 'Law' },
|
||||
P_19B: { _text: 'Directive' },
|
||||
P_19C: { _text: 'OtherBasis' },
|
||||
},
|
||||
} as any;
|
||||
|
||||
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.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);
|
||||
});
|
||||
|
||||
it('adds VAT-22 and calls generateDostawy', () => {
|
||||
const annotations = {
|
||||
NoweSrodkiTransportu: { P_42_5: { _text: '1' }, NowySrodekTransportu: [] },
|
||||
} as any;
|
||||
|
||||
const result = generateAdnotacje(annotations);
|
||||
|
||||
expect(result.some((r: any) => r?.table || r?.text?.includes('space'))).toBe(true);
|
||||
});
|
||||
|
||||
it('adds full Marża procedure with P_PMarzy_3_2', () => {
|
||||
const annotations = {
|
||||
PMarzy: { P_PMarzy: { _text: '1' }, P_PMarzy_3_2: { _text: '1' } },
|
||||
} as any;
|
||||
|
||||
const result = generateAdnotacje(annotations);
|
||||
|
||||
expect(result.flat().some((c: any) => c?.text?.includes('Adnotacje'))).toBe(true);
|
||||
});
|
||||
|
||||
it('generates all transport type combinations', () => {
|
||||
(getTable as any).mockReturnValueOnce([
|
||||
{
|
||||
P_22A: { _text: '2025-01-01' },
|
||||
P_22B: { _text: '1' },
|
||||
P_22B1: { _text: 'VIN' },
|
||||
P_22B2: { _text: 'Chassis' },
|
||||
P_22B3: { _text: 'Underbody' },
|
||||
P_22B4: { _text: 'Frame' },
|
||||
P_22C: { _text: 'C' },
|
||||
P_22C1: { _text: 'Hull' },
|
||||
P_22D: { _text: 'D' },
|
||||
P_22D1: { _text: 'Serial' },
|
||||
DetailsString: { _text: 'Description' },
|
||||
P_22BT: { _text: 'BT' },
|
||||
},
|
||||
]);
|
||||
|
||||
const result = generateDostawy({ NowySrodekTransportu: [] } as any);
|
||||
const textOutput = JSON.stringify(result);
|
||||
|
||||
expect(textOutput).toContain('VIN');
|
||||
expect(textOutput).toContain('Chassis');
|
||||
expect(textOutput).toContain('Underbody');
|
||||
expect(textOutput).toContain('Frame');
|
||||
expect(textOutput).toContain('Hull');
|
||||
expect(textOutput).toContain('Serial');
|
||||
expect(textOutput).toContain('Description');
|
||||
expect(textOutput).toContain('BT');
|
||||
});
|
||||
|
||||
it('generates only header when no details exist', () => {
|
||||
(getTable as any).mockReturnValueOnce([{ P_22A: { _text: '2025-01-01' } }]);
|
||||
const result: any = generateDostawy({ NowySrodekTransportu: [] } as any);
|
||||
|
||||
expect(result[0].table.body[0][0].text).toBe('Data dopuszczenia do użytku');
|
||||
});
|
||||
});
|
||||
206
src/lib-public/generators/FA2/Adnotacje.ts
Normal file
206
src/lib-public/generators/FA2/Adnotacje.ts
Normal file
@@ -0,0 +1,206 @@
|
||||
import { Content, ContentTable, ContentText, TableCell } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
formatText,
|
||||
getTable,
|
||||
hasValue,
|
||||
verticalSpacing,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { Adnotacje, NoweSrodkiTransportu, Zwolnienie } from '../../types/fa2.types';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { DEFAULT_TABLE_LAYOUT } from '../../../shared/consts/const';
|
||||
import { FP } from '../../types/fa1.types';
|
||||
|
||||
export function generateAdnotacje(adnotacje?: Adnotacje): Content[] {
|
||||
const result: Content[] = [];
|
||||
let firstColumn: Content[] = [];
|
||||
const secondColumn: Content[] = [];
|
||||
|
||||
if (adnotacje) {
|
||||
const zwolnienie: Zwolnienie | undefined = adnotacje.Zwolnienie;
|
||||
|
||||
if (zwolnienie?.P_19?._text === '1') {
|
||||
firstColumn.push({
|
||||
text: 'Dostawa towarów lub świadczenie usług zwolnionych od podatku na podstawie art. 43 ust. 1, art. 113 ust. 1 i 9 albo przepisów wydanych na podstawie art. 82 ust. 3 lub na podstawie innych przepisów',
|
||||
});
|
||||
if (zwolnienie.P_19A?._text) {
|
||||
firstColumn.push(
|
||||
createLabelText(
|
||||
'Podstawa zwolnienia od podatku: ',
|
||||
'Przepis ustawy albo aktu wydanego na podstawie ustawy, na podstawie którego podatnik stosuje zwolnienie od podatku'
|
||||
)
|
||||
);
|
||||
firstColumn.push(
|
||||
createLabelText('Przepis ustawy albo aktu wydanego na podstawie ustawy: ', zwolnienie.P_19A._text)
|
||||
);
|
||||
}
|
||||
if (zwolnienie.P_19B?._text) {
|
||||
firstColumn.push(
|
||||
createLabelText(
|
||||
'Podstawa zwolnienia od podatku: ',
|
||||
'Przepis dyrektywy 2006/112/WE, który zwalnia od podatku taką dostawę towarów lub takie świadczenie usług'
|
||||
)
|
||||
);
|
||||
firstColumn.push(createLabelText('Przepis dyrektywy: ', zwolnienie.P_19B._text));
|
||||
}
|
||||
if (zwolnienie.P_19C?._text) {
|
||||
firstColumn.push(
|
||||
createLabelText(
|
||||
'Podstawa zwolnienia od podatku: ',
|
||||
'Inna podstawa prawna wskazującą na to, że dostawa towarów lub świadczenie usług korzysta ze zwolnienia'
|
||||
)
|
||||
);
|
||||
firstColumn.push(createLabelText('Inna podstawa prawna: ', zwolnienie.P_19C._text));
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
adnotacje.NoweSrodkiTransportu?.P_42_5?._text === '1' ||
|
||||
adnotacje.NoweSrodkiTransportu?.P_42_5?._text === '2'
|
||||
) {
|
||||
let obowiazekVAT: Content[] = [];
|
||||
let value: string = ' ';
|
||||
|
||||
if (adnotacje.NoweSrodkiTransportu.P_42_5?._text === '1') {
|
||||
value = 'Istnieje obowiązek wystawienia dokumentu VAT-22';
|
||||
} else if (adnotacje.NoweSrodkiTransportu.P_42_5?._text === '2') {
|
||||
value = 'Nie istnieje obowiązek wystawienia dokumentu VAT-22';
|
||||
}
|
||||
obowiazekVAT = [
|
||||
...createLabelText('Wewnątrzwspólnotowe dostawy nowych środków transportu: ', value ?? ''),
|
||||
];
|
||||
if (obowiazekVAT) {
|
||||
firstColumn = [firstColumn, ...obowiazekVAT];
|
||||
}
|
||||
}
|
||||
|
||||
if (adnotacje.P_18A?._text === '1') {
|
||||
secondColumn.push({ text: 'Mechanizm podzielonej płatności' });
|
||||
}
|
||||
if (adnotacje.P_16?._text === '1') {
|
||||
secondColumn.push({ text: 'Metoda kasowa' });
|
||||
}
|
||||
if (adnotacje.P_18?._text === '1') {
|
||||
secondColumn.push({ text: 'Odwrotne obciążenie' });
|
||||
}
|
||||
if (adnotacje.P_23?._text === '1') {
|
||||
secondColumn.push({ text: 'Procedura trójstronna uproszczona' });
|
||||
}
|
||||
if (adnotacje.PMarzy?.P_PMarzy?._text === '1') {
|
||||
let valueMarzy: string = '';
|
||||
|
||||
if (adnotacje.PMarzy.P_PMarzy_3_1?._text === '1') {
|
||||
valueMarzy = 'towary używane';
|
||||
} else if (adnotacje.PMarzy.P_PMarzy_3_2?._text === '1') {
|
||||
valueMarzy = 'dzieła sztuki';
|
||||
} else if (adnotacje.PMarzy.P_PMarzy_2?._text === '1') {
|
||||
valueMarzy = 'biura podróży';
|
||||
} else if (adnotacje.PMarzy.P_PMarzy_3_3?._text === '1') {
|
||||
valueMarzy = 'przedmioty kolekcjonerskie i antyki';
|
||||
}
|
||||
secondColumn.push(createLabelText('Procedura marży: ', valueMarzy));
|
||||
}
|
||||
if (adnotacje.P_17?._text === '1') {
|
||||
secondColumn.push({ text: 'Samofakturowanie' });
|
||||
}
|
||||
if (firstColumn.length || secondColumn.length) {
|
||||
result.push({ columns: [firstColumn, secondColumn], columnGap: 20 });
|
||||
}
|
||||
|
||||
if (result.length) {
|
||||
result.unshift(verticalSpacing(1));
|
||||
result.unshift(createHeader('Adnotacje'));
|
||||
result.unshift(verticalSpacing(1));
|
||||
result.push(verticalSpacing(1));
|
||||
}
|
||||
|
||||
if (
|
||||
adnotacje.NoweSrodkiTransportu?.P_42_5?._text === '1' ||
|
||||
adnotacje.NoweSrodkiTransportu?.P_42_5?._text === '2'
|
||||
) {
|
||||
result.push(generateDostawy(adnotacje.NoweSrodkiTransportu));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function generateDostawy(noweSrodkiTransportu: NoweSrodkiTransportu): Content[] {
|
||||
const nowySrodekTransportu: Record<string, FP>[] = getTable(noweSrodkiTransportu.NowySrodekTransportu);
|
||||
let tableBody: TableCell[] = [];
|
||||
const table: ContentTable = {
|
||||
table: {
|
||||
headerRows: 1,
|
||||
widths: [100, '*'],
|
||||
body: [] as TableCell[][],
|
||||
},
|
||||
layout: DEFAULT_TABLE_LAYOUT,
|
||||
marginTop: 4,
|
||||
};
|
||||
|
||||
if (nowySrodekTransportu?.length) {
|
||||
const definedHeader: Content[] = [
|
||||
{ text: 'Data dopuszczenia do użytku', style: FormatTyp.GrayBoldTitle },
|
||||
{ text: 'Opis', style: FormatTyp.GrayBoldTitle },
|
||||
];
|
||||
|
||||
tableBody = nowySrodekTransportu.map((item: Record<string, FP>): (string | ContentText)[] => {
|
||||
const value: string[] = [];
|
||||
const anyP22B =
|
||||
hasValue(item.P_22B) ||
|
||||
hasValue(item.P_22BT) ||
|
||||
hasValue(item.P_22B1) ||
|
||||
hasValue(item.P_22B2) ||
|
||||
hasValue(item.P_22B3) ||
|
||||
hasValue(item.P_22B4);
|
||||
const anyP22C: boolean = hasValue(item.P_22C) || hasValue(item.P_22C1);
|
||||
const anyP22D: boolean = hasValue(item.P_22D) || hasValue(item.P_22D1);
|
||||
const anyP22N: boolean =
|
||||
hasValue(item.P_22B1) || hasValue(item.P_22B2) || hasValue(item.P_22B3) || hasValue(item.P_22B4);
|
||||
|
||||
if (item.P_NrWierszaNST?._text) {
|
||||
value.push(item.P_NrWierszaNST._text);
|
||||
}
|
||||
if (anyP22B) {
|
||||
value.push('Dostawa dotyczy pojazdów lądowych, o których mowa w art. 2 pkt 10 lit. a ustawy');
|
||||
} else if (anyP22C) {
|
||||
value.push('Dostawa dotyczy jednostek pływających, o których mowa w art. 2 pkt 10 lit. b ustawy');
|
||||
} else if (anyP22D) {
|
||||
value.push('Dostawa dotyczy statków powietrznych, o których mowa w art. 2 pkt 10 lit. c ustawy');
|
||||
}
|
||||
if (item.DetailsString?._text) {
|
||||
value.push(item.DetailsString._text);
|
||||
}
|
||||
if (anyP22B || anyP22C || anyP22D) {
|
||||
value.push(item.P_22B?._text ?? item.P_22C?._text ?? item.P_22D?._text ?? '');
|
||||
}
|
||||
if (item.P_22C1?._text) {
|
||||
value.push(`Numer kadłuba nowego środka transportu: ${item.P_22C1._text}`);
|
||||
}
|
||||
if (item.P_22D1?._text) {
|
||||
value.push(`Numer fabryczny nowego środka transportu: ${item.P_22D1._text}`);
|
||||
}
|
||||
if (anyP22N) {
|
||||
if (item.P_22B1?._text) {
|
||||
value.push(`Numer VIN: ${item.P_22B1._text}`);
|
||||
}
|
||||
if (item.P_22B2?._text) {
|
||||
value.push(`Numer nadwozia: ${item.P_22B2._text}`);
|
||||
}
|
||||
if (item.P_22B3?._text) {
|
||||
value.push(`Numer podwozia: ${item.P_22B3._text}`);
|
||||
}
|
||||
if (item.P_22B4?._text) {
|
||||
value.push(`Numer ramy: ${item.P_22B4._text}`);
|
||||
}
|
||||
}
|
||||
if (item.P_22BT?._text) {
|
||||
value.push(item.P_22BT._text);
|
||||
}
|
||||
return [formatText(item.P_22A?._text), { text: value.join('\n') }];
|
||||
});
|
||||
table.table.body = [[...definedHeader], ...tableBody] as TableCell[][];
|
||||
}
|
||||
|
||||
return tableBody.length ? [table, verticalSpacing(1)] : [];
|
||||
}
|
||||
46
src/lib-public/generators/FA2/Adres.spec.ts
Normal file
46
src/lib-public/generators/FA2/Adres.spec.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { describe, it, expect, vi, beforeEach, test } from 'vitest';
|
||||
import { generateAdres } from './Adres';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
formatText: vi.fn((text: string, style: string) => ({ text, style })),
|
||||
getKraj: vi.fn((code: string) => `Kraj: ${code}`),
|
||||
createLabelText: vi.fn((label: string, value: any) => [{ text: `${label}${value ?? ''}` }]),
|
||||
}));
|
||||
|
||||
import { formatText, createLabelText } from '../../../shared/PDF-functions';
|
||||
|
||||
describe(generateAdres.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test.each([
|
||||
[{ AdresL1: { _text: 'Ulica Testowa 1' } }, ['Ulica Testowa 1']],
|
||||
[{ AdresL2: { _text: '00-001 Warszawa' } }, ['00-001 Warszawa']],
|
||||
[{ KodKraju: { _text: 'PL' } }, ['Kraj: PL']],
|
||||
[
|
||||
{ AdresL1: { _text: 'Ulica 1' }, AdresL2: { _text: 'Miasto' }, KodKraju: { _text: 'DE' } },
|
||||
['Ulica 1', 'Miasto', 'Kraj: DE'],
|
||||
],
|
||||
])('generuje dane adresowe dla %s', (adres, expectedTexts) => {
|
||||
const result = generateAdres(adres as any);
|
||||
|
||||
expect(formatText).toHaveBeenCalledTimes(expectedTexts.length);
|
||||
expectedTexts.forEach((text) => {
|
||||
expect(formatText).toHaveBeenCalledWith(text, FormatTyp.Value);
|
||||
});
|
||||
|
||||
expect(createLabelText).toHaveBeenCalledWith('GLN: ', (adres as any).GLN);
|
||||
expect((result[result.length - 1] as any).text).toContain('GLN:');
|
||||
});
|
||||
|
||||
it('zwraca tylko GLN gdy brak innych pól', () => {
|
||||
const adres = { GLN: '1234567890' };
|
||||
const result = generateAdres(adres as any);
|
||||
expect(formatText).not.toHaveBeenCalled();
|
||||
expect(createLabelText).toHaveBeenCalledWith('GLN: ', '1234567890');
|
||||
expect(result).toHaveLength(1);
|
||||
expect((result[0] as any).text).toContain('GLN:');
|
||||
});
|
||||
});
|
||||
20
src/lib-public/generators/FA2/Adres.ts
Normal file
20
src/lib-public/generators/FA2/Adres.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { createLabelText, formatText, getKraj } from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { Adres } from '../../types/fa2.types';
|
||||
|
||||
export function generateAdres(adres: Adres): Content[] {
|
||||
const result: Content[] = [];
|
||||
|
||||
if (adres?.AdresL1) {
|
||||
result.push(formatText(adres.AdresL1._text, FormatTyp.Value));
|
||||
}
|
||||
if (adres?.AdresL2) {
|
||||
result.push(formatText(adres.AdresL2._text, FormatTyp.Value));
|
||||
}
|
||||
if (adres?.KodKraju) {
|
||||
result.push(formatText(getKraj(adres.KodKraju._text ?? ''), FormatTyp.Value));
|
||||
}
|
||||
result.push(...createLabelText('GLN: ', adres.GLN));
|
||||
return result;
|
||||
}
|
||||
82
src/lib-public/generators/FA2/DodatkoweInformacje.spec.ts
Normal file
82
src/lib-public/generators/FA2/DodatkoweInformacje.spec.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
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' }]),
|
||||
createSection: vi.fn((content: any, bordered: boolean) => [{ section: content, bordered }]),
|
||||
createSubHeader: vi.fn((text: string) => [{ text, style: 'subheader' }]),
|
||||
formatText: vi.fn((text: string) => ({ text, style: 'value' })),
|
||||
getValue: vi.fn((obj: any) => obj?._text ?? obj ?? ''),
|
||||
getTable: vi.fn((data: any) => data ?? []),
|
||||
getContentTable: vi.fn(() => ({ content: { text: 'mockTable' } })),
|
||||
}));
|
||||
|
||||
import {
|
||||
createHeader,
|
||||
createSection,
|
||||
createSubHeader,
|
||||
formatText,
|
||||
getValue,
|
||||
getTable,
|
||||
getContentTable,
|
||||
} from '../../../shared/PDF-functions';
|
||||
|
||||
describe(generateDodatkoweInformacje.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test.each([
|
||||
[{ TP: { _text: '1' } }, true],
|
||||
[{ ZwrotAkcyzy: { _text: '1' } }, true],
|
||||
[{ TP: { _text: '0' }, ZwrotAkcyzy: { _text: '0' } }, false],
|
||||
])('dla danych %o', (faVat, shouldHaveContent) => {
|
||||
const result = generateDodatkoweInformacje(faVat as any);
|
||||
if (shouldHaveContent) {
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
} else {
|
||||
expect(result).toEqual([]);
|
||||
}
|
||||
});
|
||||
|
||||
it('dodaje dodatkowy opis jeśli istnieje DodatkowyOpis', () => {
|
||||
(getTable as any).mockReturnValueOnce([
|
||||
{ NrWiersza: { _text: '1' }, Klucz: { _text: 'Info' }, Wartosc: { _text: 'Opis' } },
|
||||
]);
|
||||
|
||||
const faVat = {
|
||||
TP: { _text: '1' },
|
||||
DodatkowyOpis: [{ NrWiersza: { _text: '1' }, Klucz: { _text: 'Info' }, Wartosc: { _text: 'Opis' } }],
|
||||
};
|
||||
|
||||
const result = generateDodatkoweInformacje(faVat as any);
|
||||
|
||||
expect(createSubHeader).toHaveBeenCalledWith('Dodatkowy opis');
|
||||
expect(getContentTable).toHaveBeenCalled();
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
expect(createSection).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('zwraca pustą tablicę gdy brak danych wejściowych', () => {
|
||||
const result = generateDodatkoweInformacje({} as any);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('poprawnie dodaje sekcję TP i ZwrotAkcyzy razem', () => {
|
||||
const faVat = {
|
||||
TP: { _text: '1' },
|
||||
ZwrotAkcyzy: { _text: '1' },
|
||||
};
|
||||
const result = generateDodatkoweInformacje(faVat as any);
|
||||
|
||||
expect(formatText).toHaveBeenCalledWith(
|
||||
'- Istniejące powiązania między nabywcą a dokonującym dostawy towarów lub usługodawcą'
|
||||
);
|
||||
expect(formatText).toHaveBeenCalledWith(
|
||||
'- Informacja dodatkowa związana ze zwrotem podatku akcyzowego zawartego w cenie oleju napędowego'
|
||||
);
|
||||
expect(createSection).toHaveBeenCalled();
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
97
src/lib-public/generators/FA2/DodatkoweInformacje.ts
Normal file
97
src/lib-public/generators/FA2/DodatkoweInformacje.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createSection,
|
||||
createSubHeader,
|
||||
formatText,
|
||||
getContentTable,
|
||||
getTable,
|
||||
getValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { DodatkowyOpi, Fa } from '../../types/fa2.types';
|
||||
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[] = [];
|
||||
|
||||
if (getValue(faVat.TP) === '1') {
|
||||
tpLabel1.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 zwrotAkcyzyLabel: Content[] = [];
|
||||
|
||||
if (getValue(faVat.ZwrotAkcyzy) === '1') {
|
||||
zwrotAkcyzyLabel.push(
|
||||
formatText(
|
||||
'- Informacja dodatkowa związana ze zwrotem podatku akcyzowego zawartego w cenie oleju napędowego'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const labels: Content[][] = [tpLabel1, tpLabel2, zwrotAkcyzyLabel].filter(
|
||||
(el: Content[]): boolean => el.length > 0
|
||||
);
|
||||
const table: Content[] = [
|
||||
...createHeader('Dodatkowe informacje'),
|
||||
...labels,
|
||||
...generateDodatkowyOpis(faVat.DodatkowyOpis),
|
||||
];
|
||||
|
||||
return table.length > 1 ? createSection(table, true) : [];
|
||||
}
|
||||
|
||||
function generateDodatkowyOpis(fakturaZaliczkowaData: DodatkowyOpi[] | undefined): Content[] {
|
||||
if (!fakturaZaliczkowaData) {
|
||||
return [];
|
||||
}
|
||||
const fakturaZaliczkowa: DodatkowyOpi[] = getTable(fakturaZaliczkowaData)?.map(
|
||||
(item: DodatkowyOpi, index: number) => ({
|
||||
...item,
|
||||
lp: { _text: index + 1 },
|
||||
})
|
||||
);
|
||||
const table: Content[] = createSubHeader('Dodatkowy opis');
|
||||
|
||||
const fakturaZaliczkowaHeader: HeaderDefine[] = [
|
||||
{
|
||||
name: 'lp',
|
||||
title: 'Lp.',
|
||||
format: FormatTyp.Default,
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
name: 'NrWiersza',
|
||||
title: 'Numer wiersza',
|
||||
format: FormatTyp.Default,
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
name: 'Klucz',
|
||||
title: 'Rodzaj informacji',
|
||||
format: FormatTyp.Default,
|
||||
width: 'auto',
|
||||
},
|
||||
{
|
||||
name: 'Wartosc',
|
||||
title: 'Treść informacji',
|
||||
format: FormatTyp.Default,
|
||||
width: '*',
|
||||
},
|
||||
];
|
||||
const tableFakturaZaliczkowa: FormContentState = getContentTable<(typeof fakturaZaliczkowa)[0]>(
|
||||
fakturaZaliczkowaHeader,
|
||||
fakturaZaliczkowa,
|
||||
'*',
|
||||
[0, 0, 0, 0]
|
||||
);
|
||||
|
||||
if (tableFakturaZaliczkowa.content) {
|
||||
table.push(tableFakturaZaliczkowa.content);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
123
src/lib-public/generators/FA2/Platnosc.spec.ts
Normal file
123
src/lib-public/generators/FA2/Platnosc.spec.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { beforeEach, describe, expect, it, test, vi } from 'vitest';
|
||||
import { generatePlatnosc } from './Platnosc';
|
||||
import type { Platnosc, RachunekBankowy, Skonto } from '../../types/fa2.types';
|
||||
import type { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
generateLine,
|
||||
generateTwoColumns,
|
||||
getContentTable,
|
||||
hasValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { getFormaPlatnosciString } from '../../../shared/generators/common/functions';
|
||||
import { generujRachunekBankowy } from './RachunekBankowy';
|
||||
|
||||
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 ?? ''}` }]),
|
||||
generateLine: vi.fn((): Content[] => [{ line: true } as any]),
|
||||
generateTwoColumns: vi.fn((left: any[], right: any[], margins?: number[]): Content[] => [
|
||||
{ twoColumns: { left, right }, margins } as any,
|
||||
]),
|
||||
getTable: vi.fn((data: any): any[] => data ?? []),
|
||||
getValue: vi.fn((obj: any) => obj?._text ?? obj ?? ''),
|
||||
getContentTable: vi.fn(() => ({ content: [{ text: 'mockTable' }] })),
|
||||
hasValue: vi.fn((v: any) => !!v),
|
||||
}));
|
||||
|
||||
vi.mock('../../../shared/generators/common/functions', () => ({
|
||||
getFormaPlatnosciString: vi.fn((v: any) => `Forma: ${v}`),
|
||||
}));
|
||||
|
||||
vi.mock('./RachunekBankowy', () => ({
|
||||
generujRachunekBankowy: vi.fn((data: any, label: string): Content[] => [{ text: label }]),
|
||||
}));
|
||||
const mockedCreateLabelText = vi.mocked(createLabelText);
|
||||
|
||||
describe(generatePlatnosc.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
test.each([
|
||||
[
|
||||
{
|
||||
Zaplacono: { _text: '1' },
|
||||
DataZaplaty: '2025-10-01',
|
||||
FormaPlatnosci: 'Przelew',
|
||||
} as Partial<Platnosc>,
|
||||
'Zapłacono',
|
||||
],
|
||||
[
|
||||
{ ZnacznikZaplatyCzesciowej: { _text: '1' }, FormaPlatnosci: 'Gotówka' } as Partial<Platnosc>,
|
||||
'Zapłata częściowa',
|
||||
],
|
||||
[
|
||||
{ ZnacznikZaplatyCzesciowej: { _text: '2' }, FormaPlatnosci: 'Karta' } as Partial<Platnosc>,
|
||||
'Zapłata częściowa',
|
||||
],
|
||||
[{} as Partial<Platnosc>, 'Brak zapłaty'],
|
||||
])(
|
||||
'generuje poprawnie informacje o płatności dla %o',
|
||||
(platnosc: Partial<Platnosc>, expected: string): void => {
|
||||
const result: Content = generatePlatnosc(platnosc as Platnosc);
|
||||
|
||||
expect(generateLine).toHaveBeenCalled();
|
||||
expect(createHeader).toHaveBeenCalledWith('Płatność');
|
||||
|
||||
const labelCall = mockedCreateLabelText.mock.calls.find(
|
||||
([label, value]): boolean => value === expected
|
||||
) || ['defaultLabel', 'defaultValue'];
|
||||
|
||||
expect(labelCall).toBeDefined();
|
||||
expect((result as Content[]).length).toBeGreaterThan(0);
|
||||
}
|
||||
);
|
||||
|
||||
it('dodaje informacje o formie płatności jeśli hasValue zwraca true', () => {
|
||||
const platnosc: Partial<Platnosc> = { FormaPlatnosci: { _text: 'Karta' } };
|
||||
const result = generatePlatnosc(platnosc as Platnosc);
|
||||
|
||||
expect(hasValue).toHaveBeenCalledWith({ _text: 'Karta' });
|
||||
expect(getFormaPlatnosciString).toHaveBeenCalledWith({ _text: 'Karta' });
|
||||
});
|
||||
|
||||
it('generuje tabelę zapłaty częściowej i terminów płatności', () => {
|
||||
const platnosc: Partial<Platnosc> = {
|
||||
ZnacznikZaplatyCzesciowej: { _text: '1' },
|
||||
ZaplataCzesciowa: [
|
||||
{ DataZaplatyCzesciowej: { _text: '2025-10-01' }, KwotaZaplatyCzesciowej: { _text: '100' } },
|
||||
],
|
||||
TerminPlatnosci: [{ Termin: { _text: '2025-10-15' } }],
|
||||
};
|
||||
|
||||
(getContentTable as any).mockReturnValueOnce({ content: [{ text: 'mockTable1' }] });
|
||||
(getContentTable as any).mockReturnValueOnce({ content: [{ text: 'mockTable2' }] });
|
||||
|
||||
const result = generatePlatnosc(platnosc as Platnosc);
|
||||
|
||||
expect(generateTwoColumns).toHaveBeenCalled();
|
||||
expect((result as Content[]).length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('dodaje rachunki bankowe i skonto', () => {
|
||||
const platnosc: Partial<Platnosc> = {
|
||||
RachunekBankowy: ['123'] as RachunekBankowy[],
|
||||
RachunekBankowyFaktora: ['456'] as RachunekBankowy[],
|
||||
Skonto: { WarunkiSkonta: '7 dni', WysokoscSkonta: '2%' } as Skonto,
|
||||
};
|
||||
const result = generatePlatnosc(platnosc as Platnosc);
|
||||
|
||||
expect(generujRachunekBankowy).toHaveBeenCalledTimes(2);
|
||||
expect(createHeader).toHaveBeenCalledWith('Płatność');
|
||||
expect(createLabelText).toHaveBeenCalledWith('Warunki skonta: ', '7 dni');
|
||||
expect(createLabelText).toHaveBeenCalledWith('Wysokość skonta: ', '2%');
|
||||
});
|
||||
|
||||
it('zwraca pustą tablicę jeśli platnosc undefined', () => {
|
||||
const result = generatePlatnosc(undefined);
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
131
src/lib-public/generators/FA2/Platnosc.ts
Normal file
131
src/lib-public/generators/FA2/Platnosc.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
generateLine,
|
||||
generateTwoColumns,
|
||||
getContentTable,
|
||||
getTable,
|
||||
hasValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { HeaderDefine } from '../../../shared/types/pdf-types';
|
||||
import { Platnosc, TerminPlatnosci, ZaplataCzesciowa } from '../../types/fa2.types';
|
||||
import { getFormaPlatnosciString } from '../../../shared/generators/common/functions';
|
||||
import { generujRachunekBankowy } from './RachunekBankowy';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { FP } from '../../types/fa1.types';
|
||||
import { FormContentState } from '../../../shared/types/additional-data.types';
|
||||
|
||||
export function generatePlatnosc(platnosc: Platnosc | undefined): Content {
|
||||
if (!platnosc) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const terminPlatnosci: TerminPlatnosci[] = getTable(platnosc.TerminPlatnosci);
|
||||
|
||||
const zaplataCzesciowaHeader: HeaderDefine[] = [
|
||||
{
|
||||
name: 'Termin',
|
||||
title: 'Termin płatności',
|
||||
format: FormatTyp.Default,
|
||||
},
|
||||
];
|
||||
|
||||
if (terminPlatnosci.some((termin: TerminPlatnosci): FP | undefined => termin.TerminOpis)) {
|
||||
zaplataCzesciowaHeader.push({ name: 'TerminOpis', title: 'Opis płatności', format: FormatTyp.Default });
|
||||
}
|
||||
|
||||
const zaplataCzesciowaNaglowek: HeaderDefine[] = [
|
||||
{
|
||||
name: 'DataZaplatyCzesciowej',
|
||||
title: 'Data zapłaty częściowej',
|
||||
format: FormatTyp.Default,
|
||||
},
|
||||
{ name: 'KwotaZaplatyCzesciowej', title: 'Kwota zapłaty częściowej', format: FormatTyp.Currency },
|
||||
{ name: 'FormaPlatnosci', title: 'Forma płatności', format: FormatTyp.FormOfPayment },
|
||||
];
|
||||
|
||||
const table: Content[] = [generateLine(), ...createHeader('Płatność')];
|
||||
|
||||
if (platnosc.Zaplacono?._text === '1') {
|
||||
table.push(createLabelText('Informacja o płatności: ', 'Zapłacono'));
|
||||
table.push(createLabelText('Data zapłaty: ', platnosc.DataZaplaty));
|
||||
} else if (platnosc.ZnacznikZaplatyCzesciowej?._text === '1') {
|
||||
table.push(createLabelText('Informacja o płatności: ', 'Zapłata częściowa'));
|
||||
} else {
|
||||
table.push(createLabelText('Informacja o płatności: ', 'Brak zapłaty'));
|
||||
}
|
||||
|
||||
if (hasValue(platnosc.FormaPlatnosci)) {
|
||||
table.push(createLabelText('Forma płatności: ', getFormaPlatnosciString(platnosc.FormaPlatnosci)));
|
||||
} else {
|
||||
if (platnosc.OpisPlatnosci?._text) {
|
||||
table.push(createLabelText('Forma płatności: ', 'Płatność inna'));
|
||||
table.push(createLabelText('Opis płatności innej: ', platnosc.OpisPlatnosci));
|
||||
}
|
||||
}
|
||||
|
||||
const zaplataCzesciowa: ZaplataCzesciowa[] = getTable(platnosc.ZaplataCzesciowa);
|
||||
const tableZaplataCzesciowa: FormContentState = getContentTable<(typeof zaplataCzesciowa)[0]>(
|
||||
zaplataCzesciowaNaglowek,
|
||||
zaplataCzesciowa,
|
||||
'*'
|
||||
);
|
||||
|
||||
const terminPatnosciContent: TerminPlatnosci[] = terminPlatnosci.map(
|
||||
(platnosc: TerminPlatnosci): TerminPlatnosci => {
|
||||
if (!terminPlatnosci.some((termin: TerminPlatnosci): FP | undefined => termin.TerminOpis)) {
|
||||
return platnosc;
|
||||
} else {
|
||||
return {
|
||||
...platnosc,
|
||||
TerminOpis: {
|
||||
_text: `${platnosc.Termin?._text ?? ''}`,
|
||||
} as any,
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const tableTerminPlatnosci: FormContentState = getContentTable<(typeof terminPlatnosci)[0]>(
|
||||
zaplataCzesciowaHeader,
|
||||
terminPatnosciContent,
|
||||
'*'
|
||||
);
|
||||
|
||||
if (zaplataCzesciowa.length > 0 && terminPlatnosci.length > 0) {
|
||||
table.push(
|
||||
generateTwoColumns(
|
||||
tableZaplataCzesciowa.content ?? [],
|
||||
tableTerminPlatnosci.content ?? [],
|
||||
[0, 4, 0, 0]
|
||||
)
|
||||
);
|
||||
} else if (terminPlatnosci.length > 0) {
|
||||
if (tableTerminPlatnosci.content) {
|
||||
table.push(generateTwoColumns([], tableTerminPlatnosci.content));
|
||||
}
|
||||
} else if (zaplataCzesciowa.length > 0 && tableZaplataCzesciowa.content) {
|
||||
table.push(tableZaplataCzesciowa.content);
|
||||
}
|
||||
|
||||
table.push(
|
||||
generateTwoColumns(
|
||||
generujRachunekBankowy(
|
||||
getTable(platnosc.RachunekBankowy as Record<string, FP>[]),
|
||||
'Numer rachunku bankowego'
|
||||
),
|
||||
generujRachunekBankowy(
|
||||
getTable(platnosc.RachunekBankowyFaktora as Record<string, FP>[]),
|
||||
'Numer rachunku bankowego faktora'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (platnosc.Skonto) {
|
||||
table.push(createHeader('Skonto', [0, 0]));
|
||||
table.push(createLabelText('Warunki skonta: ', platnosc.Skonto.WarunkiSkonta));
|
||||
table.push(createLabelText('Wysokość skonta: ', platnosc.Skonto.WysokoscSkonta));
|
||||
}
|
||||
return table;
|
||||
}
|
||||
100
src/lib-public/generators/FA2/Podmiot1.spec.ts
Normal file
100
src/lib-public/generators/FA2/Podmiot1.spec.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generatePodmiot1 } from './Podmiot1';
|
||||
import type { Podmiot1 } from '../../types/fa2.types';
|
||||
import type { Content } from 'pdfmake/interfaces';
|
||||
import { createHeader, createLabelText, formatText } from '../../../shared/PDF-functions';
|
||||
import { generateAdres } from './Adres';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot1Dto } from './PodmiotDaneIdentyfikacyjneTPodmiot1Dto';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
|
||||
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 })),
|
||||
}));
|
||||
|
||||
vi.mock('./Adres', () => ({
|
||||
generateAdres: vi.fn((adres: any): Content[] => [{ text: 'mockAdres' }]),
|
||||
}));
|
||||
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjneTPodmiot1Dto', () => ({
|
||||
generateDaneIdentyfikacyjneTPodmiot1Dto: vi.fn((data: any): Content[] => [
|
||||
{ text: 'mockDaneIdentyfikacyjne' },
|
||||
]),
|
||||
}));
|
||||
|
||||
vi.mock('./PodmiotDaneKontaktowe', () => ({
|
||||
generateDaneKontaktowe: vi.fn((data: any): Content[] => [{ text: 'mockDaneKontaktowe' }]),
|
||||
}));
|
||||
|
||||
describe(generatePodmiot1.name, (): void => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('generates basic seller data', (): void => {
|
||||
const podmiot: Partial<Podmiot1> = {
|
||||
NrEORI: 'EORI123' as any,
|
||||
PrefiksPodatnika: 'PL' as any,
|
||||
};
|
||||
const result: Content[] = generatePodmiot1(podmiot as Podmiot1);
|
||||
|
||||
expect(createHeader).toHaveBeenCalledWith('Sprzedawca');
|
||||
expect(createLabelText).toHaveBeenCalledWith('NrEORI: ', 'EORI123');
|
||||
expect(createLabelText).toHaveBeenCalledWith('Prefiks VAT: ', 'PL');
|
||||
expect((result as any[]).some((c) => c?.[0]?.text.includes('EORI123'))).toBe(true);
|
||||
});
|
||||
|
||||
it('generates identification data if present', (): void => {
|
||||
const podmiot: Partial<Podmiot1> = {
|
||||
DaneIdentyfikacyjne: { NIP: { _text: 'nip' }, Nazwa: { _text: 'Nazwa' } },
|
||||
};
|
||||
const result: Content[] = generatePodmiot1(podmiot as Podmiot1);
|
||||
|
||||
expect(generateDaneIdentyfikacyjneTPodmiot1Dto).toHaveBeenCalledWith({
|
||||
NIP: { _text: 'nip' },
|
||||
Nazwa: { _text: 'Nazwa' },
|
||||
});
|
||||
expect(result.some((c: Content): boolean => (c as any).text === 'mockDaneIdentyfikacyjne')).toBe(true);
|
||||
});
|
||||
|
||||
it('generates address and correspondence address', (): void => {
|
||||
const podmiot: Partial<Podmiot1> = {
|
||||
Adres: { KodKraju: { _text: 'Ulica 1' } },
|
||||
AdresKoresp: { KodKraju: { _text: 'Ulica 2' } },
|
||||
};
|
||||
const result: Content[] = generatePodmiot1(podmiot as Podmiot1);
|
||||
|
||||
expect(generateAdres).toHaveBeenCalledWith({ KodKraju: { _text: 'Ulica 1' } });
|
||||
expect(generateAdres).toHaveBeenCalledWith({ KodKraju: { _text: 'Ulica 2' } });
|
||||
expect(result.some((c) => (c as any).text === 'mockAdres')).toBe(true);
|
||||
expect(formatText).toHaveBeenCalledWith('Adres', ['Label', 'LabelMargin']);
|
||||
expect(formatText).toHaveBeenCalledWith('Adres do korespondencji', ['Label', 'LabelMargin']);
|
||||
});
|
||||
|
||||
it('generates contact data and taxpayer status', (): 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', () => {
|
||||
const podmiot: Partial<Podmiot1> = {
|
||||
StatusInfoPodatnika: { _text: 'inactive' },
|
||||
};
|
||||
|
||||
const result: Content[] = generatePodmiot1(podmiot as Podmiot1);
|
||||
|
||||
expect(generateDaneKontaktowe).not.toHaveBeenCalled();
|
||||
expect(createLabelText).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Status podatnika'),
|
||||
expect.objectContaining({ _text: 'inactive' })
|
||||
);
|
||||
});
|
||||
});
|
||||
40
src/lib-public/generators/FA2/Podmiot1.ts
Normal file
40
src/lib-public/generators/FA2/Podmiot1.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { createHeader, createLabelText, formatText } 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';
|
||||
|
||||
export function generatePodmiot1(podmiot1: Podmiot1): Content[] {
|
||||
const result: Content[] = createHeader('Sprzedawca');
|
||||
|
||||
result.push(
|
||||
createLabelText('NrEORI: ', podmiot1.NrEORI),
|
||||
createLabelText('Prefiks VAT: ', podmiot1.PrefiksPodatnika)
|
||||
);
|
||||
if (podmiot1.DaneIdentyfikacyjne) {
|
||||
result.push(...generateDaneIdentyfikacyjneTPodmiot1Dto(podmiot1.DaneIdentyfikacyjne));
|
||||
}
|
||||
|
||||
if (podmiot1.Adres) {
|
||||
result.push(formatText('Adres', [FormatTyp.Label, FormatTyp.LabelMargin]), generateAdres(podmiot1.Adres));
|
||||
}
|
||||
if (podmiot1.AdresKoresp) {
|
||||
result.push(
|
||||
formatText('Adres do korespondencji', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
...generateAdres(podmiot1.AdresKoresp)
|
||||
);
|
||||
}
|
||||
if (podmiot1.DaneKontaktowe) {
|
||||
result.push(
|
||||
formatText('Dane kontaktowe', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
...generateDaneKontaktowe(podmiot1.DaneKontaktowe)
|
||||
);
|
||||
|
||||
result.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika));
|
||||
} else if (podmiot1.StatusInfoPodatnika) {
|
||||
result.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
99
src/lib-public/generators/FA2/Podmiot1Podmiot1K.spec.ts
Normal file
99
src/lib-public/generators/FA2/Podmiot1Podmiot1K.spec.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import type { Content } from 'pdfmake/interfaces';
|
||||
import type { Podmiot1, Podmiot1K } from '../../types/fa2.types';
|
||||
import { generatePodmiot1Podmiot1K } from './Podmiot1Podmiot1K';
|
||||
import { generateAdres } from './Adres';
|
||||
|
||||
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 ?? ''}` }]),
|
||||
getTable: vi.fn((data: any) => data || []),
|
||||
formatText: vi.fn((text: string, style?: any): Content => ({ text, style })),
|
||||
verticalSpacing: vi.fn((margin: number) => ({ margin })),
|
||||
}));
|
||||
|
||||
vi.mock('./Adres', () => ({
|
||||
generateAdres: vi.fn((adres: any): Content[] => [{ text: 'mockAddress' }]),
|
||||
}));
|
||||
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjneTPodmiot1Dto', async () => {
|
||||
const actual = await vi.importActual('./PodmiotDaneIdentyfikacyjneTPodmiot1Dto');
|
||||
return {
|
||||
...actual,
|
||||
generateDaneIdentyfikacyjneTPodmiot1Dto: vi.fn((data: any): Content[] => [
|
||||
{ text: 'mockDaneIdentyfikacyjne' },
|
||||
]),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('./PodmiotDaneKontaktowe', () => ({
|
||||
generateDaneKontaktowe: vi.fn((data: any): Content[] => [{ text: 'mockDaneKontaktowe' }]),
|
||||
}));
|
||||
|
||||
vi.mock('./Podmiot1Podmiot1K', async () => {
|
||||
const original: any = await vi.importActual('./Podmiot1Podmiot1K');
|
||||
return {
|
||||
...original,
|
||||
generateCorrectedContent: vi.fn((podmiot: any): Content[] => [
|
||||
{ text: `mockCorrectedContent-${podmiot?.PrefiksPodatnika?._text || 'noPrefix'}` },
|
||||
]),
|
||||
};
|
||||
});
|
||||
|
||||
describe(generatePodmiot1Podmiot1K.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('generates main header and columns', () => {
|
||||
const podmiot1: Podmiot1 = { NrEORI: '123' } as any;
|
||||
const podmiot1K: Podmiot1K = {} as any;
|
||||
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(result[2].columns[0].length).toBeGreaterThan(0);
|
||||
expect(result[2].columns[1].length).toBeGreaterThan(0);
|
||||
|
||||
expect(result[3]).toEqual({ margin: 1 });
|
||||
});
|
||||
|
||||
it('calls generateAdres if AdresKoresp exists', () => {
|
||||
const podmiot1: Podmiot1 = { NrEORI: '123', AdresKoresp: { Ulica: 'Test' } } as any;
|
||||
const podmiot1K: Podmiot1K = {} as any;
|
||||
generatePodmiot1Podmiot1K(podmiot1, podmiot1K);
|
||||
expect(generateAdres).toHaveBeenCalledWith(podmiot1.AdresKoresp);
|
||||
});
|
||||
|
||||
it('handles all fields together', () => {
|
||||
const podmiot1: Podmiot1 = {
|
||||
NrEORI: '123',
|
||||
DaneIdentyfikacyjne: { NIP: '123', Nazwa: 'Firma' } as any,
|
||||
DaneKontaktowe: [{ Telefon: '123' }] as any,
|
||||
StatusInfoPodatnika: 'active',
|
||||
AdresKoresp: { Ulica: 'Test' },
|
||||
} as any;
|
||||
const podmiot1K: Podmiot1K = { PrefiksPodatnika: { _text: 'PL' } } as any;
|
||||
const result: any = generatePodmiot1Podmiot1K(podmiot1, podmiot1K);
|
||||
|
||||
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 });
|
||||
});
|
||||
});
|
||||
73
src/lib-public/generators/FA2/Podmiot1Podmiot1K.ts
Normal file
73
src/lib-public/generators/FA2/Podmiot1Podmiot1K.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
formatText,
|
||||
getTable,
|
||||
verticalSpacing,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { Podmiot1, Podmiot1K } from '../../types/fa2.types';
|
||||
import { generateAdres } from './Adres';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot1Dto } from './PodmiotDaneIdentyfikacyjneTPodmiot1Dto';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
|
||||
export function generatePodmiot1Podmiot1K(podmiot1: Podmiot1, podmiot1K: Podmiot1K): Content[] {
|
||||
const result: Content[] = createHeader('Sprzedawca');
|
||||
let firstColumn: Content[] = [];
|
||||
let secondColumn: Content[] = [];
|
||||
|
||||
firstColumn.push(createHeader('Dane identyfikacyjne'), createLabelText('Numer EORI: ', podmiot1.NrEORI));
|
||||
if (podmiot1.DaneIdentyfikacyjne) {
|
||||
firstColumn.push(...generateDaneIdentyfikacyjneTPodmiot1Dto(podmiot1.DaneIdentyfikacyjne));
|
||||
}
|
||||
|
||||
if (podmiot1.DaneKontaktowe) {
|
||||
firstColumn.push(generateDaneKontaktowe(getTable(podmiot1.DaneKontaktowe)));
|
||||
}
|
||||
if (podmiot1.StatusInfoPodatnika) {
|
||||
firstColumn.push(createLabelText('Status podatnika: ', podmiot1.StatusInfoPodatnika));
|
||||
}
|
||||
if (firstColumn.length) {
|
||||
result.push({
|
||||
columns: [firstColumn, []],
|
||||
columnGap: 20,
|
||||
});
|
||||
}
|
||||
firstColumn = generateCorrectedContent(podmiot1K);
|
||||
secondColumn = generateCorrectedContent(podmiot1);
|
||||
|
||||
if (podmiot1.AdresKoresp) {
|
||||
secondColumn.push(
|
||||
formatText('Adres do korespondencji', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
generateAdres(podmiot1.AdresKoresp)
|
||||
);
|
||||
}
|
||||
if (firstColumn.length || secondColumn.length) {
|
||||
result.push({
|
||||
columns: [firstColumn, secondColumn],
|
||||
columnGap: 20,
|
||||
});
|
||||
}
|
||||
if (result.length) {
|
||||
result.push(verticalSpacing(1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function generateCorrectedContent(podmiot: Podmiot1 | Podmiot1K): Content[] {
|
||||
const result: Content[] = [];
|
||||
|
||||
result.push(createHeader('Treść korygowana'));
|
||||
|
||||
if (podmiot.PrefiksPodatnika?._text) {
|
||||
result.push(createLabelText('Prefiks VAT: ', podmiot.PrefiksPodatnika));
|
||||
}
|
||||
if (podmiot.DaneIdentyfikacyjne) {
|
||||
result.push(...generateDaneIdentyfikacyjneTPodmiot1Dto(podmiot.DaneIdentyfikacyjne));
|
||||
}
|
||||
if (podmiot.Adres) {
|
||||
result.push(formatText('Adres', [FormatTyp.Label, FormatTyp.LabelMargin]), generateAdres(podmiot.Adres));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
80
src/lib-public/generators/FA2/Podmiot1Podmiot1K2.spec.ts
Normal file
80
src/lib-public/generators/FA2/Podmiot1Podmiot1K2.spec.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { generateCorrectedContent } from './Podmiot1Podmiot1K';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import type { Content } from 'pdfmake/interfaces';
|
||||
import { FP, Podmiot1K } from '../../types/fa2.types';
|
||||
|
||||
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 })),
|
||||
verticalSpacing: vi.fn().mockImplementation((size) => ({ margin: size })),
|
||||
}));
|
||||
|
||||
vi.mock('./Adres', () => ({
|
||||
generateAdres: vi.fn((adres: any): Content[] => [{ text: 'mockAdres' }]),
|
||||
}));
|
||||
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjneTPodmiot1Dto', () => ({
|
||||
generateDaneIdentyfikacyjneTPodmiot1Dto: vi.fn((data: any): Content[] => [
|
||||
{ text: 'mockDaneIdentyfikacyjne' },
|
||||
]),
|
||||
}));
|
||||
|
||||
vi.mock('./PodmiotDaneKontaktowe', () => ({
|
||||
generateDaneKontaktowe: vi.fn((data: any): Content[] => [{ text: 'mockDaneKontaktowe' }]),
|
||||
}));
|
||||
|
||||
describe(generateCorrectedContent.name, () => {
|
||||
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);
|
||||
});
|
||||
|
||||
it('should generate corrected content with prefixPodatnika ', () => {
|
||||
const podmiot: Podmiot1K = { PrefiksPodatnika: { _text: 'tekst' } };
|
||||
const result: Content[] = generateCorrectedContent(podmiot);
|
||||
expect(result.length).equal(2);
|
||||
|
||||
expect((result[0] as any).some((c: any) => c.text === 'Treść korygowana')).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);
|
||||
expect(result.length).equal(2);
|
||||
expect((result[0] as any).some((c: any) => c.text === 'Treść korygowana')).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);
|
||||
expect(result.length).equal(3);
|
||||
expect((result[0] as any).some((c: any) => c.text === 'Treść korygowana')).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);
|
||||
});
|
||||
|
||||
it('handles all fields together', () => {
|
||||
const podmiot: Podmiot1K = {
|
||||
PrefiksPodatnika: { _text: 'PL' },
|
||||
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);
|
||||
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);
|
||||
expect((result[3] as any).text.includes('Adres')).toBe(true);
|
||||
expect((result[4] as any).some((c: { text: string }) => c.text === 'mockAdres')).toBe(true);
|
||||
|
||||
expect(result.length).toBe(5);
|
||||
});
|
||||
});
|
||||
108
src/lib-public/generators/FA2/Podmiot2.spec.ts
Normal file
108
src/lib-public/generators/FA2/Podmiot2.spec.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import type { Content } from 'pdfmake/interfaces';
|
||||
import type { FP, Podmiot2 } from '../../types/fa2.types';
|
||||
import { generatePodmiot2 } from './Podmiot2';
|
||||
import { createHeader, createLabelText, formatText } from '../../../shared/PDF-functions';
|
||||
import { generateAdres } from './Adres';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot2Dto } from './PodmiotDaneIdentyfikacyjneTPodmiot2Dto';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
|
||||
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 })),
|
||||
}));
|
||||
|
||||
vi.mock('./Adres', async () => {
|
||||
const actual = await vi.importActual('./Adres');
|
||||
return {
|
||||
...actual,
|
||||
generateAdres: vi.fn((adres: any): Content[] => [{ text: 'mockAddress' }]),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjneTPodmiot2Dto', async () => {
|
||||
const actual = await vi.importActual('./PodmiotDaneIdentyfikacyjneTPodmiot2Dto');
|
||||
return {
|
||||
...actual,
|
||||
generateDaneIdentyfikacyjneTPodmiot2Dto: vi.fn((data: any): Content[] => [
|
||||
{ text: 'mockDaneIdentyfikacyjne' },
|
||||
]),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('./PodmiotDaneKontaktowe', async () => {
|
||||
const actual = await vi.importActual('./PodmiotDaneKontaktowe');
|
||||
return {
|
||||
...actual,
|
||||
generateDaneKontaktowe: vi.fn((data: any): Content[] => [{ text: 'mockDaneKontaktowe' }]),
|
||||
};
|
||||
});
|
||||
|
||||
describe(generatePodmiot2.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('generates basic header and identifiers', () => {
|
||||
const podmiot: Partial<Podmiot2> = { IDNabywcy: 'ID123' as FP, NrEORI: 'EORI123' as FP };
|
||||
const result = generatePodmiot2(podmiot as Podmiot2);
|
||||
|
||||
expect(createHeader).toHaveBeenCalledWith('Nabywca');
|
||||
expect(createLabelText).toHaveBeenCalledWith('Identyfikator nabywcy: ', 'ID123');
|
||||
expect(createLabelText).toHaveBeenCalledWith('NrEORI: ', 'EORI123');
|
||||
expect(result[0]).toEqual({ text: 'Nabywca', style: 'header' });
|
||||
});
|
||||
|
||||
it('generates identification data if provided', () => {
|
||||
const podmiot: Partial<Podmiot2> = {
|
||||
DaneIdentyfikacyjne: { NIP: '123', Nazwa: 'Firma' } as any,
|
||||
};
|
||||
const result = generatePodmiot2(podmiot as Podmiot2);
|
||||
|
||||
expect(generateDaneIdentyfikacyjneTPodmiot2Dto).toHaveBeenCalledWith(podmiot.DaneIdentyfikacyjne);
|
||||
expect(result.some((c: any) => c.text === 'mockDaneIdentyfikacyjne')).toBe(true);
|
||||
});
|
||||
|
||||
it('generates address and correspondence address', () => {
|
||||
const podmiot: Partial<Podmiot2> = {
|
||||
Adres: { KodKraju: 'PL' } as any,
|
||||
AdresKoresp: { KodKraju: 'PL-K' } as any,
|
||||
};
|
||||
const result = generatePodmiot2(podmiot as Podmiot2);
|
||||
|
||||
expect(generateAdres).toHaveBeenCalledWith(podmiot.Adres);
|
||||
expect(generateAdres).toHaveBeenCalledWith(podmiot.AdresKoresp);
|
||||
expect(formatText).toHaveBeenCalledWith('Adres', ['Label', 'LabelMargin']);
|
||||
expect(formatText).toHaveBeenCalledWith('Adres do korespondencji', ['Label', 'LabelMargin']);
|
||||
expect(result.some((c: any) => c.text === 'mockAddress')).toBe(true);
|
||||
});
|
||||
|
||||
it('generates contact data and client number if provided', () => {
|
||||
const podmiot: Partial<Podmiot2> = {
|
||||
DaneKontaktowe: [{ Telefon: '123' }] as any,
|
||||
NrKlienta: 'CL123' as FP,
|
||||
};
|
||||
const result = generatePodmiot2(podmiot as Podmiot2);
|
||||
|
||||
expect(generateDaneKontaktowe).toHaveBeenCalledWith(podmiot.DaneKontaktowe);
|
||||
expect(createLabelText).toHaveBeenCalledWith('Numer klienta: ', 'CL123');
|
||||
expect(result.some((c: any) => c.text === 'mockDaneKontaktowe')).toBe(true);
|
||||
});
|
||||
|
||||
it('handles all fields together', () => {
|
||||
const podmiot: Partial<Podmiot2> = {
|
||||
DaneIdentyfikacyjne: { NIP: '123', Nazwa: 'Firma' } as any,
|
||||
Adres: { KodKraju: 'PL' } as any,
|
||||
AdresKoresp: { KodKraju: 'PL-K' } as any,
|
||||
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(
|
||||
result.filter((c: any): boolean => c.text === 'mockAddress').length + (result as any)[5].length
|
||||
).toBe(2);
|
||||
expect(result.some((c: any): boolean => c.text === 'mockDaneKontaktowe')).toBe(true);
|
||||
});
|
||||
});
|
||||
42
src/lib-public/generators/FA2/Podmiot2.ts
Normal file
42
src/lib-public/generators/FA2/Podmiot2.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { createHeader, createLabelText, formatText } from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { Podmiot2 } from '../../types/fa2.types';
|
||||
import { generateAdres } from './Adres';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot2Dto } from './PodmiotDaneIdentyfikacyjneTPodmiot2Dto';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
import { DaneIdentyfikacyjneTPodmiot2Dto } from '../../types/fa2-additional-types';
|
||||
|
||||
export function generatePodmiot2(podmiot2: Podmiot2): Content[] {
|
||||
const result: Content[] = createHeader('Nabywca');
|
||||
|
||||
result.push(
|
||||
createLabelText('Identyfikator nabywcy: ', podmiot2.IDNabywcy),
|
||||
createLabelText('NrEORI: ', podmiot2.NrEORI)
|
||||
);
|
||||
if (podmiot2.DaneIdentyfikacyjne) {
|
||||
result.push(
|
||||
...generateDaneIdentyfikacyjneTPodmiot2Dto(
|
||||
podmiot2.DaneIdentyfikacyjne as DaneIdentyfikacyjneTPodmiot2Dto
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (podmiot2.Adres) {
|
||||
result.push(formatText('Adres', [FormatTyp.Label, FormatTyp.LabelMargin]), generateAdres(podmiot2.Adres));
|
||||
}
|
||||
if (podmiot2.AdresKoresp) {
|
||||
result.push(
|
||||
formatText('Adres do korespondencji', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
...generateAdres(podmiot2.AdresKoresp)
|
||||
);
|
||||
}
|
||||
if (podmiot2.DaneKontaktowe) {
|
||||
result.push(
|
||||
formatText('Dane kontaktowe', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
...generateDaneKontaktowe(podmiot2.DaneKontaktowe),
|
||||
createLabelText('Numer klienta: ', podmiot2.NrKlienta)
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
109
src/lib-public/generators/FA2/Podmiot2Podmiot2k.spec.ts
Normal file
109
src/lib-public/generators/FA2/Podmiot2Podmiot2k.spec.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import type { Content } from 'pdfmake/interfaces';
|
||||
import type { Podmiot2, Podmiot2K } from '../../types/fa2.types';
|
||||
|
||||
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 })),
|
||||
getTable: vi.fn((data: any) => data || []),
|
||||
hasValue: vi.fn((value: any) => value !== undefined && value !== null),
|
||||
verticalSpacing: vi.fn((margin: number) => ({ margin })),
|
||||
}));
|
||||
|
||||
vi.mock('./Adres', () => ({
|
||||
generateAdres: vi.fn((adres: any): Content[] => [{ text: 'mockAddress' }]),
|
||||
}));
|
||||
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjneTPodmiot1Dto', () => ({
|
||||
generateDaneIdentyfikacyjneTPodmiot1Dto: vi.fn((data: any): Content[] => [
|
||||
{ text: 'mockDaneIdentyfikacyjne' },
|
||||
]),
|
||||
}));
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
it('generates header and first column with ID, contact, and client number', () => {
|
||||
const podmiot2: Podmiot2 = {
|
||||
NrEORI: 'EORI123',
|
||||
DaneKontaktowe: [{ Telefon: '123' }],
|
||||
NrKlienta: 'CL123',
|
||||
} as any;
|
||||
const podmiot2K: Podmiot2K = { IDNabywcy: 'ID123' } as any;
|
||||
const result = generatePodmiot2Podmiot2K(podmiot2, podmiot2K) as any;
|
||||
expect(result[0]).toEqual({ text: 'Nabywca', 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(result[2].columns[0].length).toBeGreaterThan(0);
|
||||
expect(result[2].columns[1].length).toBeGreaterThan(0);
|
||||
|
||||
expect(result[3]).toEqual({ margin: 1 });
|
||||
});
|
||||
|
||||
it('calls generateAdres if AdresKoresp exists', () => {
|
||||
const podmiot2: Podmiot2 = { NrEORI: 'EORI123', AdresKoresp: { Ulica: 'Test' } } as any;
|
||||
const podmiot2K: Podmiot2K = {} as any;
|
||||
generatePodmiot2Podmiot2K(podmiot2, podmiot2K);
|
||||
expect(generateAdres).toHaveBeenCalledWith(podmiot2.AdresKoresp);
|
||||
});
|
||||
|
||||
it('generates corrected content columns', () => {
|
||||
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', () => {
|
||||
const podmiot2: Podmiot2 = { NrEORI: 'EORI123' } as any;
|
||||
const podmiot2K: Podmiot2K = {} as any;
|
||||
const result = generatePodmiot2Podmiot2K(podmiot2, podmiot2K);
|
||||
|
||||
expect(result[result.length - 1]).toEqual({ margin: 1 });
|
||||
});
|
||||
|
||||
it('handles all fields together', () => {
|
||||
const podmiot2: Podmiot2 = {
|
||||
NrEORI: 'EORI123',
|
||||
DaneIdentyfikacyjne: { NIP: '123' } as any,
|
||||
DaneKontaktowe: [{ Telefon: '123' }],
|
||||
NrKlienta: 'CL123',
|
||||
AdresKoresp: { Ulica: 'Test' },
|
||||
} 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');
|
||||
});
|
||||
});
|
||||
74
src/lib-public/generators/FA2/Podmiot2Podmiot2k.ts
Normal file
74
src/lib-public/generators/FA2/Podmiot2Podmiot2k.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
formatText,
|
||||
getTable,
|
||||
hasValue,
|
||||
verticalSpacing,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { Podmiot2, Podmiot2K } from '../../types/fa3.types';
|
||||
import { generateAdres } from './Adres';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot1Dto } from './PodmiotDaneIdentyfikacyjneTPodmiot1Dto';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
|
||||
export function generatePodmiot2Podmiot2K(podmiot2: Podmiot2, podmiot2K: Podmiot2K): Content[] {
|
||||
const result: Content[] = createHeader('Nabywca');
|
||||
let firstColumn: Content[] = [];
|
||||
let secondColumn: Content[] = [];
|
||||
|
||||
firstColumn.push(createHeader('Dane identyfikacyjne'), createLabelText('Numer EORI: ', podmiot2.NrEORI));
|
||||
if (podmiot2.DaneIdentyfikacyjne) {
|
||||
firstColumn.push(...generateDaneIdentyfikacyjneTPodmiot1Dto(podmiot2.DaneIdentyfikacyjne));
|
||||
}
|
||||
|
||||
if (podmiot2.DaneKontaktowe) {
|
||||
firstColumn.push(generateDaneKontaktowe(getTable(podmiot2.DaneKontaktowe)));
|
||||
}
|
||||
if (podmiot2.NrKlienta) {
|
||||
firstColumn.push(createLabelText('Numer klienta: ', podmiot2.NrKlienta));
|
||||
}
|
||||
if (firstColumn.length) {
|
||||
result.push({
|
||||
columns: [firstColumn, []],
|
||||
columnGap: 20,
|
||||
});
|
||||
}
|
||||
firstColumn = generateCorrectedContent(podmiot2K);
|
||||
secondColumn = generateCorrectedContent(podmiot2);
|
||||
if (podmiot2.AdresKoresp) {
|
||||
secondColumn.push(
|
||||
formatText('Adres do korespondencji', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
generateAdres(podmiot2.AdresKoresp)
|
||||
);
|
||||
}
|
||||
|
||||
if (firstColumn.length || secondColumn.length) {
|
||||
result.push({
|
||||
columns: [firstColumn, secondColumn],
|
||||
columnGap: 20,
|
||||
});
|
||||
}
|
||||
if (result.length) {
|
||||
result.push(verticalSpacing(1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function generateCorrectedContent(podmiot: Podmiot2 | Podmiot2K): Content[] {
|
||||
const result: Content[] = [];
|
||||
|
||||
result.push(createHeader('Treść korygowana'));
|
||||
|
||||
if (hasValue(podmiot.IDNabywcy)) {
|
||||
result.push(createLabelText('Identyfikator nabywcy: ', podmiot.IDNabywcy));
|
||||
}
|
||||
if (podmiot.DaneIdentyfikacyjne) {
|
||||
result.push(...generateDaneIdentyfikacyjneTPodmiot1Dto(podmiot.DaneIdentyfikacyjne));
|
||||
}
|
||||
if (podmiot.Adres) {
|
||||
result.push(formatText('Adres', [FormatTyp.Label, FormatTyp.LabelMargin]), generateAdres(podmiot.Adres));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
134
src/lib-public/generators/FA2/Podmiot3.spec.ts
Normal file
134
src/lib-public/generators/FA2/Podmiot3.spec.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { generatePodmiot3 } from './Podmiot3';
|
||||
import type { Podmiot3 } from '../../types/fa2.types';
|
||||
import * as PDFFunctions from '../../../shared/PDF-functions';
|
||||
import * as AdresModule from './Adres';
|
||||
import * as DaneIdModule from './PodmiotDaneIdentyfikacyjneTPodmiot3Dto';
|
||||
import * as DaneKontaktoweModule from './PodmiotDaneKontaktowe';
|
||||
import * as CommonFunctions from '../../../shared/generators/common/functions';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions');
|
||||
vi.mock('./Adres');
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjneTPodmiot3Dto');
|
||||
vi.mock('./PodmiotDaneKontaktowe');
|
||||
vi.mock('../../../shared/generators/common/functions');
|
||||
|
||||
describe(generatePodmiot3.name, () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.mocked(PDFFunctions.createHeader).mockImplementation((text) => [{ text }]);
|
||||
vi.mocked(PDFFunctions.createLabelText).mockImplementation((label, value) => [
|
||||
{ text: `${label}${value ?? ''}` },
|
||||
]);
|
||||
vi.mocked(PDFFunctions.formatText).mockImplementation((text, style) => ({ text, style }) as any);
|
||||
vi.mocked(PDFFunctions.generateLine).mockReturnValue({ line: true } as any);
|
||||
vi.mocked(PDFFunctions.generateTwoColumns).mockImplementation((c1, c2) => ({ columns: [c1, c2] }));
|
||||
|
||||
vi.mocked(AdresModule.generateAdres).mockReturnValue([{ text: 'mockAddress' }]);
|
||||
vi.mocked(DaneIdModule.generateDaneIdentyfikacyjneTPodmiot3Dto).mockReturnValue([
|
||||
{ text: 'mockDaneIdentyfikacyjne' },
|
||||
]);
|
||||
vi.mocked(DaneKontaktoweModule.generateDaneKontaktowe).mockReturnValue([{ text: 'mockDaneKontaktowe' }]);
|
||||
vi.mocked(CommonFunctions.getRolaString).mockReturnValue('mockRola');
|
||||
});
|
||||
|
||||
it('generates minimal podmiot3 structure', () => {
|
||||
const podmiot: Podmiot3 = { IDNabywcy: 'ID1', NrEORI: 'EORI1', DaneIdentyfikacyjne: {} } as any;
|
||||
const result = generatePodmiot3(podmiot, 0) as any;
|
||||
|
||||
expect(result[0]).toEqual({ line: true });
|
||||
expect(result[1]).toHaveProperty('columns');
|
||||
expect(result[1].columns[0].length).toBeGreaterThan(0);
|
||||
expect(result[1].columns[1].length).toBe(0);
|
||||
});
|
||||
|
||||
it('adds column2 when Adres is present', () => {
|
||||
const podmiot: Podmiot3 = {
|
||||
IDNabywcy: 'ID1',
|
||||
NrEORI: 'EORI1',
|
||||
DaneIdentyfikacyjne: {},
|
||||
Adres: {},
|
||||
} as any;
|
||||
|
||||
const result = generatePodmiot3(podmiot, 0) as any;
|
||||
const column2 = result[1].columns[1];
|
||||
|
||||
expect(column2[0]).toHaveProperty('text', 'Adres');
|
||||
expect(column2[1]).toEqual([{ text: 'mockAddress' }]);
|
||||
});
|
||||
|
||||
it('adds column2 when AdresKoresp is present', () => {
|
||||
const podmiot: Podmiot3 = {
|
||||
IDNabywcy: 'ID1',
|
||||
NrEORI: 'EORI1',
|
||||
DaneIdentyfikacyjne: {},
|
||||
AdresKoresp: {},
|
||||
} as any;
|
||||
|
||||
const result = generatePodmiot3(podmiot, 0) as any;
|
||||
const column2 = result[1].columns[1];
|
||||
|
||||
expect(column2[0]).toHaveProperty('text', 'Adres do korespondencji');
|
||||
expect(column2[1]).toEqual({ text: 'mockAddress' });
|
||||
});
|
||||
|
||||
it('adds column2 when DaneKontaktowe and NrKlienta are present', () => {
|
||||
const podmiot: Podmiot3 = {
|
||||
IDNabywcy: 'ID1',
|
||||
NrEORI: 'EORI1',
|
||||
DaneIdentyfikacyjne: {},
|
||||
DaneKontaktowe: [{}],
|
||||
NrKlienta: '1234',
|
||||
} as any;
|
||||
|
||||
const result = generatePodmiot3(podmiot, 0) as any;
|
||||
const column2 = result[1].columns[1];
|
||||
|
||||
expect(column2[0]).toHaveProperty('text', 'Dane kontaktowe');
|
||||
expect(column2[1]).toEqual({ text: 'mockDaneKontaktowe' });
|
||||
expect(column2[2]).toEqual([{ text: 'Numer klienta: 1234' }]);
|
||||
});
|
||||
|
||||
it('handles all fields together', () => {
|
||||
const podmiot: Podmiot3 = {
|
||||
IDNabywcy: 'ID1',
|
||||
NrEORI: 'EORI1',
|
||||
DaneIdentyfikacyjne: {},
|
||||
Rola: 2,
|
||||
OpisRoli: 'opisRoli',
|
||||
Udzial: '50%',
|
||||
Adres: {},
|
||||
AdresKoresp: {},
|
||||
DaneKontaktowe: [{}],
|
||||
NrKlienta: '1234',
|
||||
} as any;
|
||||
|
||||
const result = generatePodmiot3(podmiot, 1) as any;
|
||||
const column1 = result[1].columns[0] as any;
|
||||
const column2 = result[1].columns[1] as any;
|
||||
|
||||
const flattenContent = (arr: any[]): any[] =>
|
||||
arr.flatMap((item) => (Array.isArray(item) ? flattenContent(item) : item));
|
||||
|
||||
const flatColumn1 = flattenContent(column1);
|
||||
const flatColumn2 = flattenContent(column2);
|
||||
|
||||
expect(flatColumn1.some((c) => typeof c.text === 'string' && c.text.includes('Podmiot inny 2'))).toBe(
|
||||
true
|
||||
);
|
||||
expect(
|
||||
flatColumn1.some((c) => typeof c.text === 'string' && c.text.includes('Identyfikator nabywcy: ID1'))
|
||||
).toBe(true);
|
||||
expect(flatColumn1.some((c) => typeof c.text === 'string' && c.text.includes('Rola: mockRola'))).toBe(
|
||||
true
|
||||
);
|
||||
expect(
|
||||
flatColumn1.some((c) => typeof c.text === 'string' && c.text.includes('Rola inna: opisRoli'))
|
||||
).toBe(true);
|
||||
expect(flatColumn1.some((c) => typeof c.text === 'string' && c.text.includes('Udział: 50%'))).toBe(true);
|
||||
|
||||
expect(flatColumn2.some((c) => c.text === 'mockAddress')).toBe(true);
|
||||
expect(flatColumn2.some((c) => c.text === 'mockDaneKontaktowe')).toBe(true);
|
||||
expect(flatColumn2.some((c) => c.text === 'Numer klienta: 1234')).toBe(true);
|
||||
});
|
||||
});
|
||||
50
src/lib-public/generators/FA2/Podmiot3.ts
Normal file
50
src/lib-public/generators/FA2/Podmiot3.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
formatText,
|
||||
generateLine,
|
||||
generateTwoColumns,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { Podmiot3 } from '../../types/fa2.types';
|
||||
import { generateAdres } from './Adres';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot3Dto } from './PodmiotDaneIdentyfikacyjneTPodmiot3Dto';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
import { getRolaString } from '../../../shared/generators/common/functions';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
|
||||
export function generatePodmiot3(podmiot: Podmiot3, index: number): Content[] {
|
||||
const result: Content[] = [];
|
||||
|
||||
result.push(generateLine());
|
||||
const column1: Content[] = [
|
||||
...createHeader(`Podmiot inny ${index + 1}`),
|
||||
createLabelText('Identyfikator nabywcy: ', podmiot.IDNabywcy),
|
||||
createLabelText('NrEORI: ', podmiot.NrEORI),
|
||||
...generateDaneIdentyfikacyjneTPodmiot3Dto(podmiot.DaneIdentyfikacyjne),
|
||||
createLabelText('Rola: ', getRolaString(podmiot.Rola, 2)),
|
||||
createLabelText('Rola inna: ', podmiot.OpisRoli),
|
||||
createLabelText('Udział: ', podmiot.Udzial, [FormatTyp.Percentage]),
|
||||
];
|
||||
|
||||
const column2: Content[] = [];
|
||||
|
||||
if (podmiot.Adres) {
|
||||
column2.push(formatText('Adres', [FormatTyp.Label, FormatTyp.LabelMargin]), generateAdres(podmiot.Adres));
|
||||
}
|
||||
if (podmiot.AdresKoresp) {
|
||||
column2.push(
|
||||
formatText('Adres do korespondencji', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
...generateAdres(podmiot.AdresKoresp)
|
||||
);
|
||||
}
|
||||
if (podmiot.DaneKontaktowe) {
|
||||
column2.push(
|
||||
formatText('Dane kontaktowe', [FormatTyp.Label, FormatTyp.LabelMargin]),
|
||||
...generateDaneKontaktowe(podmiot.DaneKontaktowe),
|
||||
createLabelText('Numer klienta: ', podmiot.NrKlienta)
|
||||
);
|
||||
}
|
||||
result.push(generateTwoColumns(column1, column2));
|
||||
return result;
|
||||
}
|
||||
74
src/lib-public/generators/FA2/Podmiot3Podmiot2k.spec.ts
Normal file
74
src/lib-public/generators/FA2/Podmiot3Podmiot2k.spec.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot3Dto } from './Podmiot3Podmiot2k';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn((text: string) => [`header:${text}`]),
|
||||
createLabelText: vi.fn((label: string, value: any) => [`label:${label}${value}`]),
|
||||
generateTwoColumns: vi.fn((col1: any, col2: any) => ({ columns: [col1, col2] })),
|
||||
getTable: vi.fn((data: any) => (data ? ['table:data'] : [])),
|
||||
hasValue: vi.fn((val: any) => val !== undefined && val !== null && val !== ''),
|
||||
}));
|
||||
|
||||
vi.mock('../../../shared/generators/common/functions', () => ({
|
||||
getRolaString: vi.fn((rola: any) => `rola:${rola}`),
|
||||
}));
|
||||
|
||||
vi.mock('./PodmiotAdres', () => ({
|
||||
generatePodmiotAdres: vi.fn((adres: any, label?: string) => [`adres:${label ?? ''}`]),
|
||||
}));
|
||||
|
||||
vi.mock('./PodmiotDaneIdentyfikacyjneTPodmiot2Dto', () => ({
|
||||
generateDaneIdentyfikacyjneTPodmiot2Dto: vi.fn((data: any) => [`dane:${data}`]),
|
||||
}));
|
||||
|
||||
vi.mock('./PodmiotDaneKontaktowe', () => ({
|
||||
generateDaneKontaktowe: vi.fn((data: any) => [`kontakt:${data}`]),
|
||||
}));
|
||||
|
||||
describe(generateDaneIdentyfikacyjneTPodmiot3Dto.name, () => {
|
||||
it('should return empty array when input is undefined', () => {
|
||||
const result = generateDaneIdentyfikacyjneTPodmiot3Dto(undefined, 0);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should generate full structure with all fields', () => {
|
||||
const podmiotDto = {
|
||||
fakturaPodmiotNDto: {
|
||||
NrEORI: 'EORI123',
|
||||
Rola: 'R',
|
||||
OpisRoli: 'OpisRoli',
|
||||
Udzial: 100,
|
||||
DaneKontaktowe: [{ email: 'test@test.com' }],
|
||||
NrKlienta: 'K123',
|
||||
IDNabywcy: 'ID1',
|
||||
DaneIdentyfikacyjne: 'Dane1',
|
||||
Adres: 'Adres1',
|
||||
AdresKoresp: 'AdresKoresp1',
|
||||
},
|
||||
podmiot2KDto: {
|
||||
IDNabywcy: 'ID2',
|
||||
DaneIdentyfikacyjne: 'Dane2',
|
||||
Adres: 'Adres2',
|
||||
},
|
||||
};
|
||||
|
||||
const result = generateDaneIdentyfikacyjneTPodmiot3Dto(podmiotDto as any, 0);
|
||||
|
||||
expect(result[0]).toEqual('header:Podmiot inny 1');
|
||||
|
||||
expect(result.some((r: any) => Array.isArray(r) && r[0].startsWith('label:'))).toBe(true);
|
||||
|
||||
expect(result.some((r: any) => r.columns)).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle missing optional fields gracefully', () => {
|
||||
const podmiotDto = {
|
||||
fakturaPodmiotNDto: {},
|
||||
podmiot2KDto: {},
|
||||
};
|
||||
|
||||
const result = generateDaneIdentyfikacyjneTPodmiot3Dto(podmiotDto as any, 1);
|
||||
|
||||
expect(result[0]).toEqual('header:Podmiot inny 2');
|
||||
});
|
||||
});
|
||||
77
src/lib-public/generators/FA2/Podmiot3Podmiot2k.ts
Normal file
77
src/lib-public/generators/FA2/Podmiot3Podmiot2k.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import {
|
||||
createHeader,
|
||||
createLabelText,
|
||||
generateTwoColumns,
|
||||
getTable,
|
||||
hasValue,
|
||||
} from '../../../shared/PDF-functions';
|
||||
import { Podmiot3Podmiot2KDto } from '../../types/fa2-additional-types';
|
||||
import { getRolaString } from '../../../shared/generators/common/functions';
|
||||
import { generatePodmiotAdres } from './PodmiotAdres';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot2Dto } from './PodmiotDaneIdentyfikacyjneTPodmiot2Dto';
|
||||
import { generateDaneKontaktowe } from './PodmiotDaneKontaktowe';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { Podmiot1DaneKontaktowe, Podmiot2K, Podmiot3 } from '../../types/fa2.types';
|
||||
import { Adres } from '../../types/fa1.types';
|
||||
|
||||
export function generateDaneIdentyfikacyjneTPodmiot3Dto(
|
||||
podmiot2KDto: Podmiot3Podmiot2KDto | undefined,
|
||||
index: number
|
||||
): Content[] {
|
||||
if (!podmiot2KDto) {
|
||||
return [];
|
||||
}
|
||||
const podmiot1: Podmiot3 = podmiot2KDto.fakturaPodmiotNDto;
|
||||
const podmiot1DaneKontaktowe: Podmiot1DaneKontaktowe[] = getTable(podmiot1.DaneKontaktowe);
|
||||
const podmiot1K: (Podmiot2K & { Adres?: Adres }) | undefined = podmiot2KDto.podmiot2KDto;
|
||||
const result: Content[] = createHeader(`Podmiot inny ${index + 1}`);
|
||||
|
||||
if (
|
||||
hasValue(podmiot1.NrEORI) ||
|
||||
hasValue(podmiot1.Rola) ||
|
||||
hasValue(podmiot1.OpisRoli) ||
|
||||
hasValue(podmiot1?.Udzial)
|
||||
) {
|
||||
result.push(
|
||||
...createHeader('Dane identyfikacyjne'),
|
||||
createLabelText('Numer EORI: ', podmiot1.NrEORI),
|
||||
createLabelText('Rola: ', getRolaString(podmiot1.Rola, 2)),
|
||||
createLabelText('Rola inna: ', podmiot1.OpisRoli),
|
||||
createLabelText('Udział: ', podmiot1.Udzial, FormatTyp.Currency6)
|
||||
);
|
||||
}
|
||||
|
||||
if (podmiot1DaneKontaktowe.length > 0 || hasValue(podmiot1.NrKlienta)) {
|
||||
result.push(generateDaneKontaktowe(podmiot1.DaneKontaktowe ?? []));
|
||||
result.push(createLabelText('Numer klienta: ', podmiot1.NrKlienta));
|
||||
}
|
||||
const columns1: Content[] = [
|
||||
...createHeader('Treść korygowana'),
|
||||
createLabelText('Identyfikator nabywcy: ', podmiot1K?.IDNabywcy),
|
||||
];
|
||||
|
||||
if (podmiot1K?.DaneIdentyfikacyjne) {
|
||||
columns1.push(generateDaneIdentyfikacyjneTPodmiot2Dto(podmiot1K.DaneIdentyfikacyjne));
|
||||
}
|
||||
if (podmiot1K?.Adres) {
|
||||
columns1.push(generatePodmiotAdres(podmiot1K.Adres));
|
||||
}
|
||||
const columns2: Content[] = [
|
||||
...createHeader('Treść korygująca'),
|
||||
createLabelText('Identyfikator nabywcy: ', podmiot1?.IDNabywcy),
|
||||
];
|
||||
|
||||
if (podmiot1?.DaneIdentyfikacyjne) {
|
||||
columns2.push(generateDaneIdentyfikacyjneTPodmiot2Dto(podmiot1.DaneIdentyfikacyjne));
|
||||
}
|
||||
if (podmiot1?.Adres) {
|
||||
columns2.push(generatePodmiotAdres(podmiot1.Adres));
|
||||
}
|
||||
|
||||
if (podmiot1.AdresKoresp != null) {
|
||||
columns2.push(generatePodmiotAdres(podmiot1.AdresKoresp, 'Adres korespondencyjny'));
|
||||
}
|
||||
result.push(generateTwoColumns(columns1, columns2));
|
||||
return result;
|
||||
}
|
||||
64
src/lib-public/generators/FA2/PodmiotAdres.spec.ts
Normal file
64
src/lib-public/generators/FA2/PodmiotAdres.spec.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { generatePodmiotAdres } from './PodmiotAdres';
|
||||
import { createHeader, createSubHeader } from '../../../shared/PDF-functions';
|
||||
import { generateAdres } from './Adres';
|
||||
import { Adres } from '../../types/fa2.types';
|
||||
import { Margins } from 'pdfmake/interfaces';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createHeader: vi.fn().mockReturnValue([{ text: 'Header' }]),
|
||||
createSubHeader: vi.fn().mockReturnValue([{ text: 'SubHeader' }]),
|
||||
}));
|
||||
|
||||
vi.mock('./Adres', () => ({
|
||||
generateAdres: vi.fn().mockReturnValue([{ text: 'Adres' }]),
|
||||
}));
|
||||
|
||||
describe(generatePodmiotAdres.name, () => {
|
||||
const mockAdres: Adres = {
|
||||
ulica: 'Testowa',
|
||||
nrDomu: '1',
|
||||
kodPocztowy: '00-000',
|
||||
miejscowosc: 'Warszawa',
|
||||
} as Adres;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('returns an empty array when podmiotAdres is undefined', () => {
|
||||
const result = generatePodmiotAdres(undefined);
|
||||
expect(result).toEqual([]);
|
||||
expect(createHeader).not.toHaveBeenCalled();
|
||||
expect(createSubHeader).not.toHaveBeenCalled();
|
||||
expect(generateAdres).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('uses createHeader when isSubheader is false by default', () => {
|
||||
const result = generatePodmiotAdres(mockAdres);
|
||||
expect(createHeader).toHaveBeenCalledWith('Adres', undefined);
|
||||
expect(createSubHeader).not.toHaveBeenCalled();
|
||||
expect(generateAdres).toHaveBeenCalledWith(mockAdres);
|
||||
expect(result).toEqual([{ text: 'Header' }, { text: 'Adres' }]);
|
||||
});
|
||||
|
||||
it('uses createSubHeader when isSubheader is true', () => {
|
||||
const result = generatePodmiotAdres(mockAdres, 'Location', true);
|
||||
expect(createSubHeader).toHaveBeenCalledWith('Location', undefined);
|
||||
expect(createHeader).not.toHaveBeenCalled();
|
||||
expect(generateAdres).toHaveBeenCalledWith(mockAdres);
|
||||
expect(result).toEqual([{ text: 'SubHeader' }, { text: 'Adres' }]);
|
||||
});
|
||||
|
||||
it('passes headerMargin to createHeader', () => {
|
||||
const mockMargin: Margins = [10, 20, 30, 40];
|
||||
generatePodmiotAdres(mockAdres, 'Adres', false, mockMargin);
|
||||
expect(createHeader).toHaveBeenCalledWith('Adres', mockMargin);
|
||||
});
|
||||
|
||||
it('passes headerMargin to createSubHeader', () => {
|
||||
const mockMargin: Margins = [5, 5, 5, 5];
|
||||
generatePodmiotAdres(mockAdres, 'Header', true, mockMargin);
|
||||
expect(createSubHeader).toHaveBeenCalledWith('Header', mockMargin);
|
||||
});
|
||||
});
|
||||
19
src/lib-public/generators/FA2/PodmiotAdres.ts
Normal file
19
src/lib-public/generators/FA2/PodmiotAdres.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Content, Margins } from 'pdfmake/interfaces';
|
||||
import { createHeader, createSubHeader } from '../../../shared/PDF-functions';
|
||||
import { Adres } from '../../types/fa2.types';
|
||||
import { generateAdres } from './Adres';
|
||||
|
||||
export function generatePodmiotAdres(
|
||||
podmiotAdres: Adres | undefined,
|
||||
headerTitle = 'Adres',
|
||||
isSubheader = false,
|
||||
headerMargin?: Margins
|
||||
): Content[] {
|
||||
if (!podmiotAdres) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
...(isSubheader ? createSubHeader(headerTitle, headerMargin) : createHeader(headerTitle, headerMargin)),
|
||||
...generateAdres(podmiotAdres),
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import type { DaneIdentyfikacyjne } from '../../types/fa2.types';
|
||||
import { createLabelText } from '../../../shared/PDF-functions';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot1Dto } from './PodmiotDaneIdentyfikacyjneTPodmiot1Dto';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createLabelText: vi.fn((label: string, value: string) => ({ text: `${label}${value}` })),
|
||||
}));
|
||||
|
||||
describe(generateDaneIdentyfikacyjneTPodmiot1Dto.name, () => {
|
||||
const mockData: DaneIdentyfikacyjne = {
|
||||
NIP: '1234567890',
|
||||
Nazwa: 'Test Company',
|
||||
} as DaneIdentyfikacyjne;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('calls createLabelText twice with correct arguments', () => {
|
||||
const result = generateDaneIdentyfikacyjneTPodmiot1Dto(mockData);
|
||||
expect(createLabelText).toHaveBeenCalledTimes(2);
|
||||
expect(createLabelText).toHaveBeenCalledWith('NIP: ', '1234567890');
|
||||
expect(createLabelText).toHaveBeenCalledWith('Nazwa: ', 'Test Company');
|
||||
expect(result).toEqual([{ text: 'NIP: 1234567890' }, { text: 'Nazwa: Test Company' }]);
|
||||
});
|
||||
|
||||
it('handles empty values correctly', () => {
|
||||
const result = generateDaneIdentyfikacyjneTPodmiot1Dto({ NIP: '', Nazwa: '' } as DaneIdentyfikacyjne);
|
||||
expect(createLabelText).toHaveBeenCalledWith('NIP: ', '');
|
||||
expect(createLabelText).toHaveBeenCalledWith('Nazwa: ', '');
|
||||
expect(result).toEqual([{ text: 'NIP: ' }, { text: 'Nazwa: ' }]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Content } from 'pdfmake/interfaces';
|
||||
import { DaneIdentyfikacyjne } from '../../types/fa2.types';
|
||||
import { createLabelText } from '../../../shared/PDF-functions';
|
||||
|
||||
export function generateDaneIdentyfikacyjneTPodmiot1Dto(daneIdentyfikacyjne: DaneIdentyfikacyjne): Content[] {
|
||||
return [
|
||||
createLabelText('NIP: ', daneIdentyfikacyjne.NIP),
|
||||
createLabelText('Nazwa: ', daneIdentyfikacyjne.Nazwa),
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import FormatTyp from '../../../shared/enums/common.enum';
|
||||
import { createLabelText, createLabelTextArray, formatText } from '../../../shared/PDF-functions';
|
||||
import { generateDaneIdentyfikacyjneTPodmiot2Dto } from './PodmiotDaneIdentyfikacyjneTPodmiot2Dto';
|
||||
import { DaneIdentyfikacyjneTPodmiot2Dto } from '../../types/fa2-additional-types';
|
||||
|
||||
vi.mock('../../../shared/PDF-functions', () => ({
|
||||
createLabelText: vi.fn((label: string, value: any) => ({ text: `${label}${value?._text ?? value}` })),
|
||||
createLabelTextArray: vi.fn((arr: any[]) => ({ text: arr.map((a) => a.value?._text ?? a.value).join('') })),
|
||||
formatText: vi.fn((text: string, type: FormatTyp) => ({ text, type })),
|
||||
}));
|
||||
|
||||
describe(generateDaneIdentyfikacyjneTPodmiot2Dto.name, () => {
|
||||
const baseData: DaneIdentyfikacyjneTPodmiot2Dto = {
|
||||
NIP: { _text: '1234567890' },
|
||||
Nazwa: { _text: 'Test Company' },
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('always includes NIP and Nazwa', () => {
|
||||
const result = generateDaneIdentyfikacyjneTPodmiot2Dto(baseData);
|
||||
expect(createLabelText).toHaveBeenCalledWith('NIP: ', baseData.NIP);
|
||||
expect(createLabelText).toHaveBeenCalledWith('Nazwa: ', baseData.Nazwa);
|
||||
expect(result).toContainEqual({ text: 'NIP: 1234567890' });
|
||||
expect(result).toContainEqual({ text: 'Nazwa: Test Company' });
|
||||
});
|
||||
|
||||
it('adds VAT-UE section when NrVatUE is present', () => {
|
||||
const data: DaneIdentyfikacyjneTPodmiot2Dto = {
|
||||
...baseData,
|
||||
NrVatUE: { _text: '123' },
|
||||
KodUE: { _text: 'PL' },
|
||||
};
|
||||
const result = generateDaneIdentyfikacyjneTPodmiot2Dto(data);
|
||||
expect(createLabelTextArray).toHaveBeenCalledWith([
|
||||
{ value: 'Numer VAT-UE: ', formatTyp: FormatTyp.Label },
|
||||
{ value: data.KodUE, formatTyp: FormatTyp.Value },
|
||||
{ value: ' ' },
|
||||
{ value: data.NrVatUE, formatTyp: FormatTyp.Value },
|
||||
]);
|
||||
expect(result.some((r: any) => r.text.includes('Numer VAT-UE'))).toBe(true);
|
||||
});
|
||||
|
||||
it('adds KodKraju section when KodKraju is present', () => {
|
||||
const data: DaneIdentyfikacyjneTPodmiot2Dto = {
|
||||
...baseData,
|
||||
KodKraju: { _text: 'DE' },
|
||||
NrID: { _text: '999999' },
|
||||
};
|
||||
const result = generateDaneIdentyfikacyjneTPodmiot2Dto(data);
|
||||
expect(createLabelTextArray).toHaveBeenCalledWith([
|
||||
{ value: 'Identyfikator podatkowy inny: ', formatTyp: FormatTyp.Label },
|
||||
{ value: data.KodKraju, formatTyp: FormatTyp.Value },
|
||||
{ value: ' ' },
|
||||
{ value: data.NrID, formatTyp: FormatTyp.Value },
|
||||
]);
|
||||
expect(result.some((r: any) => (r as any).text.includes('Identyfikator podatkowy inny'))).toBe(true);
|
||||
});
|
||||
|
||||
it('adds "Brak identyfikatora" when BrakID._text is "1"', () => {
|
||||
const data: DaneIdentyfikacyjneTPodmiot2Dto = {
|
||||
...baseData,
|
||||
BrakID: { _text: '1' },
|
||||
};
|
||||
const result = generateDaneIdentyfikacyjneTPodmiot2Dto(data);
|
||||
expect(formatText).toHaveBeenCalledWith('Brak identyfikatora', FormatTyp.Label);
|
||||
expect(result.some((r) => (r as any).text === 'Brak identyfikatora')).toBe(true);
|
||||
});
|
||||
|
||||
it('does not add extra sections when optional fields are missing', () => {
|
||||
const result = generateDaneIdentyfikacyjneTPodmiot2Dto(baseData);
|
||||
expect(createLabelTextArray).not.toHaveBeenCalled();
|
||||
expect(formatText).not.toHaveBeenCalled();
|
||||
expect(result).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user