@fin.cx/skr 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/index.d.ts +6 -0
- package/dist_ts/index.js +7 -1
- package/dist_ts/plugins.d.ts +8 -1
- package/dist_ts/plugins.js +10 -2
- package/dist_ts/skr.api.d.ts +70 -0
- package/dist_ts/skr.api.js +348 -1
- package/dist_ts/skr.export.accounts.d.ts +53 -0
- package/dist_ts/skr.export.accounts.js +111 -0
- package/dist_ts/skr.export.balances.d.ts +59 -0
- package/dist_ts/skr.export.balances.js +205 -0
- package/dist_ts/skr.export.d.ts +110 -0
- package/dist_ts/skr.export.js +315 -0
- package/dist_ts/skr.export.ledger.d.ts +95 -0
- package/dist_ts/skr.export.ledger.js +164 -0
- package/dist_ts/skr.export.pdf.d.ts +82 -0
- package/dist_ts/skr.export.pdf.js +548 -0
- package/dist_ts/skr.invoice.adapter.d.ts +98 -0
- package/dist_ts/skr.invoice.adapter.js +476 -0
- package/dist_ts/skr.invoice.booking.d.ts +102 -0
- package/dist_ts/skr.invoice.booking.js +556 -0
- package/dist_ts/skr.invoice.entity.d.ts +287 -0
- package/dist_ts/skr.invoice.entity.js +2 -0
- package/dist_ts/skr.invoice.mapper.d.ts +69 -0
- package/dist_ts/skr.invoice.mapper.js +401 -0
- package/dist_ts/skr.invoice.storage.d.ts +140 -0
- package/dist_ts/skr.invoice.storage.js +529 -0
- package/dist_ts/skr.security.d.ts +65 -0
- package/dist_ts/skr.security.js +319 -0
- package/dist_ts/skr.types.d.ts +1 -0
- package/package.json +17 -12
- package/readme.md +207 -16
- package/ts/index.ts +6 -0
- package/ts/plugins.ts +22 -1
- package/ts/skr.api.ts +485 -0
- package/ts/skr.export.accounts.ts +154 -0
- package/ts/skr.export.balances.ts +270 -0
- package/ts/skr.export.ledger.ts +249 -0
- package/ts/skr.export.pdf.ts +601 -0
- package/ts/skr.export.ts +443 -0
- package/ts/skr.invoice.adapter.ts +581 -0
- package/ts/skr.invoice.booking.ts +738 -0
- package/ts/skr.invoice.entity.ts +351 -0
- package/ts/skr.invoice.mapper.ts +486 -0
- package/ts/skr.invoice.storage.ts +710 -0
- package/ts/skr.security.ts +405 -0
- package/ts/skr.types.ts +1 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { ITrialBalanceReport, IIncomeStatement, IBalanceSheet } from './skr.types.js';
|
|
2
|
+
export interface IPdfReportOptions {
|
|
3
|
+
companyName: string;
|
|
4
|
+
companyAddress?: string;
|
|
5
|
+
taxId?: string;
|
|
6
|
+
registrationNumber?: string;
|
|
7
|
+
fiscalYear: number;
|
|
8
|
+
dateFrom: Date;
|
|
9
|
+
dateTo: Date;
|
|
10
|
+
preparedBy?: string;
|
|
11
|
+
preparedDate?: Date;
|
|
12
|
+
}
|
|
13
|
+
export declare class PdfReportGenerator {
|
|
14
|
+
private exportPath;
|
|
15
|
+
private options;
|
|
16
|
+
private pdfInstance;
|
|
17
|
+
constructor(exportPath: string, options: IPdfReportOptions);
|
|
18
|
+
/**
|
|
19
|
+
* Initializes the PDF generator
|
|
20
|
+
*/
|
|
21
|
+
initialize(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Generates the trial balance PDF report
|
|
24
|
+
*/
|
|
25
|
+
generateTrialBalancePdf(report: ITrialBalanceReport): Promise<Buffer>;
|
|
26
|
+
/**
|
|
27
|
+
* Generates the income statement PDF report
|
|
28
|
+
*/
|
|
29
|
+
generateIncomeStatementPdf(report: IIncomeStatement): Promise<Buffer>;
|
|
30
|
+
/**
|
|
31
|
+
* Generates the balance sheet PDF report
|
|
32
|
+
*/
|
|
33
|
+
generateBalanceSheetPdf(report: IBalanceSheet): Promise<Buffer>;
|
|
34
|
+
/**
|
|
35
|
+
* Generates the comprehensive Jahresabschluss PDF
|
|
36
|
+
*/
|
|
37
|
+
generateJahresabschlussPdf(trialBalance: ITrialBalanceReport, incomeStatement: IIncomeStatement, balanceSheet: IBalanceSheet): Promise<Buffer>;
|
|
38
|
+
/**
|
|
39
|
+
* Generates HTML for trial balance report
|
|
40
|
+
*/
|
|
41
|
+
private generateTrialBalanceHtml;
|
|
42
|
+
/**
|
|
43
|
+
* Generates HTML for income statement report
|
|
44
|
+
*/
|
|
45
|
+
private generateIncomeStatementHtml;
|
|
46
|
+
/**
|
|
47
|
+
* Generates HTML for balance sheet report
|
|
48
|
+
*/
|
|
49
|
+
private generateBalanceSheetHtml;
|
|
50
|
+
/**
|
|
51
|
+
* Generates comprehensive Jahresabschluss HTML
|
|
52
|
+
*/
|
|
53
|
+
private generateJahresabschlussHtml;
|
|
54
|
+
/**
|
|
55
|
+
* Generates the report header
|
|
56
|
+
*/
|
|
57
|
+
private generateHeader;
|
|
58
|
+
/**
|
|
59
|
+
* Generates the report footer
|
|
60
|
+
*/
|
|
61
|
+
private generateFooter;
|
|
62
|
+
/**
|
|
63
|
+
* Gets the base CSS styles for all reports
|
|
64
|
+
*/
|
|
65
|
+
private getBaseStyles;
|
|
66
|
+
/**
|
|
67
|
+
* Formats number in German format (1.234,56)
|
|
68
|
+
*/
|
|
69
|
+
private formatGermanNumber;
|
|
70
|
+
/**
|
|
71
|
+
* Formats date in German format (DD.MM.YYYY)
|
|
72
|
+
*/
|
|
73
|
+
private formatGermanDate;
|
|
74
|
+
/**
|
|
75
|
+
* Saves a PDF report to the export directory
|
|
76
|
+
*/
|
|
77
|
+
savePdfReport(filename: string, pdfBuffer: Buffer): Promise<string>;
|
|
78
|
+
/**
|
|
79
|
+
* Closes the PDF generator
|
|
80
|
+
*/
|
|
81
|
+
close(): Promise<void>;
|
|
82
|
+
}
|
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
export class PdfReportGenerator {
|
|
4
|
+
constructor(exportPath, options) {
|
|
5
|
+
this.pdfInstance = null;
|
|
6
|
+
this.exportPath = exportPath;
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Initializes the PDF generator
|
|
11
|
+
*/
|
|
12
|
+
async initialize() {
|
|
13
|
+
this.pdfInstance = new plugins.smartpdf.SmartPdf();
|
|
14
|
+
await this.pdfInstance.start();
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generates the trial balance PDF report
|
|
18
|
+
*/
|
|
19
|
+
async generateTrialBalancePdf(report) {
|
|
20
|
+
if (!this.pdfInstance) {
|
|
21
|
+
throw new Error('PDF generator not initialized');
|
|
22
|
+
}
|
|
23
|
+
const html = this.generateTrialBalanceHtml(report);
|
|
24
|
+
const pdfResult = await this.pdfInstance.getA4PdfResultForHtmlString(html);
|
|
25
|
+
return Buffer.from(pdfResult.buffer);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Generates the income statement PDF report
|
|
29
|
+
*/
|
|
30
|
+
async generateIncomeStatementPdf(report) {
|
|
31
|
+
if (!this.pdfInstance) {
|
|
32
|
+
throw new Error('PDF generator not initialized');
|
|
33
|
+
}
|
|
34
|
+
const html = this.generateIncomeStatementHtml(report);
|
|
35
|
+
const pdfResult = await this.pdfInstance.getA4PdfResultForHtmlString(html);
|
|
36
|
+
return Buffer.from(pdfResult.buffer);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Generates the balance sheet PDF report
|
|
40
|
+
*/
|
|
41
|
+
async generateBalanceSheetPdf(report) {
|
|
42
|
+
if (!this.pdfInstance) {
|
|
43
|
+
throw new Error('PDF generator not initialized');
|
|
44
|
+
}
|
|
45
|
+
const html = this.generateBalanceSheetHtml(report);
|
|
46
|
+
const pdfResult = await this.pdfInstance.getA4PdfResultForHtmlString(html);
|
|
47
|
+
return Buffer.from(pdfResult.buffer);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Generates the comprehensive Jahresabschluss PDF
|
|
51
|
+
*/
|
|
52
|
+
async generateJahresabschlussPdf(trialBalance, incomeStatement, balanceSheet) {
|
|
53
|
+
if (!this.pdfInstance) {
|
|
54
|
+
throw new Error('PDF generator not initialized');
|
|
55
|
+
}
|
|
56
|
+
const html = this.generateJahresabschlussHtml(trialBalance, incomeStatement, balanceSheet);
|
|
57
|
+
const pdfResult = await this.pdfInstance.getA4PdfResultForHtmlString(html);
|
|
58
|
+
return Buffer.from(pdfResult.buffer);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Generates HTML for trial balance report
|
|
62
|
+
*/
|
|
63
|
+
generateTrialBalanceHtml(report) {
|
|
64
|
+
const entries = report.entries || [];
|
|
65
|
+
const tableRows = entries.map(entry => `
|
|
66
|
+
<tr>
|
|
67
|
+
<td>${entry.accountNumber}</td>
|
|
68
|
+
<td>${entry.accountName}</td>
|
|
69
|
+
<td class="number">${this.formatGermanNumber(0)}</td>
|
|
70
|
+
<td class="number">${this.formatGermanNumber(entry.debitBalance)}</td>
|
|
71
|
+
<td class="number">${this.formatGermanNumber(entry.creditBalance)}</td>
|
|
72
|
+
<td class="number">${this.formatGermanNumber(entry.netBalance)}</td>
|
|
73
|
+
</tr>
|
|
74
|
+
`).join('');
|
|
75
|
+
return `
|
|
76
|
+
<!DOCTYPE html>
|
|
77
|
+
<html>
|
|
78
|
+
<head>
|
|
79
|
+
<meta charset="UTF-8">
|
|
80
|
+
<style>
|
|
81
|
+
${this.getBaseStyles()}
|
|
82
|
+
</style>
|
|
83
|
+
</head>
|
|
84
|
+
<body>
|
|
85
|
+
${this.generateHeader('Summen- und Saldenliste')}
|
|
86
|
+
|
|
87
|
+
<table class="report-table">
|
|
88
|
+
<thead>
|
|
89
|
+
<tr>
|
|
90
|
+
<th>Konto</th>
|
|
91
|
+
<th>Bezeichnung</th>
|
|
92
|
+
<th>Anfangssaldo</th>
|
|
93
|
+
<th>Soll</th>
|
|
94
|
+
<th>Haben</th>
|
|
95
|
+
<th>Saldo</th>
|
|
96
|
+
</tr>
|
|
97
|
+
</thead>
|
|
98
|
+
<tbody>
|
|
99
|
+
${tableRows}
|
|
100
|
+
</tbody>
|
|
101
|
+
<tfoot>
|
|
102
|
+
<tr class="total-row">
|
|
103
|
+
<td colspan="3">Summe</td>
|
|
104
|
+
<td class="number">${this.formatGermanNumber(report.totalDebits)}</td>
|
|
105
|
+
<td class="number">${this.formatGermanNumber(report.totalCredits)}</td>
|
|
106
|
+
<td class="number">${this.formatGermanNumber(report.totalDebits - report.totalCredits)}</td>
|
|
107
|
+
</tr>
|
|
108
|
+
</tfoot>
|
|
109
|
+
</table>
|
|
110
|
+
|
|
111
|
+
${this.generateFooter()}
|
|
112
|
+
</body>
|
|
113
|
+
</html>
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Generates HTML for income statement report
|
|
118
|
+
*/
|
|
119
|
+
generateIncomeStatementHtml(report) {
|
|
120
|
+
const revenueRows = (report.revenue || []).map(entry => `
|
|
121
|
+
<tr>
|
|
122
|
+
<td>${entry.accountNumber}</td>
|
|
123
|
+
<td>${entry.accountName}</td>
|
|
124
|
+
<td class="number">${this.formatGermanNumber(entry.amount)}</td>
|
|
125
|
+
</tr>
|
|
126
|
+
`).join('');
|
|
127
|
+
const expenseRows = (report.expenses || []).map(entry => `
|
|
128
|
+
<tr>
|
|
129
|
+
<td>${entry.accountNumber}</td>
|
|
130
|
+
<td>${entry.accountName}</td>
|
|
131
|
+
<td class="number">${this.formatGermanNumber(entry.amount)}</td>
|
|
132
|
+
</tr>
|
|
133
|
+
`).join('');
|
|
134
|
+
return `
|
|
135
|
+
<!DOCTYPE html>
|
|
136
|
+
<html>
|
|
137
|
+
<head>
|
|
138
|
+
<meta charset="UTF-8">
|
|
139
|
+
<style>
|
|
140
|
+
${this.getBaseStyles()}
|
|
141
|
+
</style>
|
|
142
|
+
</head>
|
|
143
|
+
<body>
|
|
144
|
+
${this.generateHeader('Gewinn- und Verlustrechnung')}
|
|
145
|
+
|
|
146
|
+
<h2>Erträge</h2>
|
|
147
|
+
<table class="report-table">
|
|
148
|
+
<thead>
|
|
149
|
+
<tr>
|
|
150
|
+
<th>Konto</th>
|
|
151
|
+
<th>Bezeichnung</th>
|
|
152
|
+
<th>Betrag</th>
|
|
153
|
+
</tr>
|
|
154
|
+
</thead>
|
|
155
|
+
<tbody>
|
|
156
|
+
${revenueRows}
|
|
157
|
+
</tbody>
|
|
158
|
+
<tfoot>
|
|
159
|
+
<tr class="subtotal-row">
|
|
160
|
+
<td colspan="2">Summe Erträge</td>
|
|
161
|
+
<td class="number">${this.formatGermanNumber(report.totalRevenue)}</td>
|
|
162
|
+
</tr>
|
|
163
|
+
</tfoot>
|
|
164
|
+
</table>
|
|
165
|
+
|
|
166
|
+
<h2>Aufwendungen</h2>
|
|
167
|
+
<table class="report-table">
|
|
168
|
+
<thead>
|
|
169
|
+
<tr>
|
|
170
|
+
<th>Konto</th>
|
|
171
|
+
<th>Bezeichnung</th>
|
|
172
|
+
<th>Betrag</th>
|
|
173
|
+
</tr>
|
|
174
|
+
</thead>
|
|
175
|
+
<tbody>
|
|
176
|
+
${expenseRows}
|
|
177
|
+
</tbody>
|
|
178
|
+
<tfoot>
|
|
179
|
+
<tr class="subtotal-row">
|
|
180
|
+
<td colspan="2">Summe Aufwendungen</td>
|
|
181
|
+
<td class="number">${this.formatGermanNumber(report.totalExpenses)}</td>
|
|
182
|
+
</tr>
|
|
183
|
+
</tfoot>
|
|
184
|
+
</table>
|
|
185
|
+
|
|
186
|
+
<div class="result-section">
|
|
187
|
+
<h2>Ergebnis</h2>
|
|
188
|
+
<table class="summary-table">
|
|
189
|
+
<tr>
|
|
190
|
+
<td>Erträge</td>
|
|
191
|
+
<td class="number">${this.formatGermanNumber(report.totalRevenue)}</td>
|
|
192
|
+
</tr>
|
|
193
|
+
<tr>
|
|
194
|
+
<td>Aufwendungen</td>
|
|
195
|
+
<td class="number">- ${this.formatGermanNumber(report.totalExpenses)}</td>
|
|
196
|
+
</tr>
|
|
197
|
+
<tr class="total-row">
|
|
198
|
+
<td>${report.netIncome >= 0 ? 'Jahresüberschuss' : 'Jahresfehlbetrag'}</td>
|
|
199
|
+
<td class="number ${report.netIncome >= 0 ? 'positive' : 'negative'}">
|
|
200
|
+
${this.formatGermanNumber(report.netIncome)}
|
|
201
|
+
</td>
|
|
202
|
+
</tr>
|
|
203
|
+
</table>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
${this.generateFooter()}
|
|
207
|
+
</body>
|
|
208
|
+
</html>
|
|
209
|
+
`;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Generates HTML for balance sheet report
|
|
213
|
+
*/
|
|
214
|
+
generateBalanceSheetHtml(report) {
|
|
215
|
+
const assetRows = [...(report.assets.current || []), ...(report.assets.fixed || [])].map(entry => `
|
|
216
|
+
<tr>
|
|
217
|
+
<td>${entry.accountNumber}</td>
|
|
218
|
+
<td>${entry.accountName}</td>
|
|
219
|
+
<td class="number">${this.formatGermanNumber(entry.amount)}</td>
|
|
220
|
+
</tr>
|
|
221
|
+
`).join('');
|
|
222
|
+
const liabilityRows = [...(report.liabilities.current || []), ...(report.liabilities.longTerm || [])].map(entry => `
|
|
223
|
+
<tr>
|
|
224
|
+
<td>${entry.accountNumber}</td>
|
|
225
|
+
<td>${entry.accountName}</td>
|
|
226
|
+
<td class="number">${this.formatGermanNumber(entry.amount)}</td>
|
|
227
|
+
</tr>
|
|
228
|
+
`).join('');
|
|
229
|
+
const equityRows = (report.equity.entries || []).map(entry => `
|
|
230
|
+
<tr>
|
|
231
|
+
<td>${entry.accountNumber}</td>
|
|
232
|
+
<td>${entry.accountName}</td>
|
|
233
|
+
<td class="number">${this.formatGermanNumber(entry.amount)}</td>
|
|
234
|
+
</tr>
|
|
235
|
+
`).join('');
|
|
236
|
+
return `
|
|
237
|
+
<!DOCTYPE html>
|
|
238
|
+
<html>
|
|
239
|
+
<head>
|
|
240
|
+
<meta charset="UTF-8">
|
|
241
|
+
<style>
|
|
242
|
+
${this.getBaseStyles()}
|
|
243
|
+
</style>
|
|
244
|
+
</head>
|
|
245
|
+
<body>
|
|
246
|
+
${this.generateHeader('Bilanz')}
|
|
247
|
+
|
|
248
|
+
<div class="balance-sheet">
|
|
249
|
+
<div class="aktiva">
|
|
250
|
+
<h2>Aktiva</h2>
|
|
251
|
+
<table class="report-table">
|
|
252
|
+
<thead>
|
|
253
|
+
<tr>
|
|
254
|
+
<th>Konto</th>
|
|
255
|
+
<th>Bezeichnung</th>
|
|
256
|
+
<th>Betrag</th>
|
|
257
|
+
</tr>
|
|
258
|
+
</thead>
|
|
259
|
+
<tbody>
|
|
260
|
+
${assetRows}
|
|
261
|
+
</tbody>
|
|
262
|
+
<tfoot>
|
|
263
|
+
<tr class="total-row">
|
|
264
|
+
<td colspan="2">Summe Aktiva</td>
|
|
265
|
+
<td class="number">${this.formatGermanNumber(report.assets.totalAssets)}</td>
|
|
266
|
+
</tr>
|
|
267
|
+
</tfoot>
|
|
268
|
+
</table>
|
|
269
|
+
</div>
|
|
270
|
+
|
|
271
|
+
<div class="passiva">
|
|
272
|
+
<h2>Passiva</h2>
|
|
273
|
+
|
|
274
|
+
<h3>Eigenkapital</h3>
|
|
275
|
+
<table class="report-table">
|
|
276
|
+
<tbody>
|
|
277
|
+
${equityRows}
|
|
278
|
+
</tbody>
|
|
279
|
+
<tfoot>
|
|
280
|
+
<tr class="subtotal-row">
|
|
281
|
+
<td colspan="2">Summe Eigenkapital</td>
|
|
282
|
+
<td class="number">${this.formatGermanNumber(report.equity.totalEquity)}</td>
|
|
283
|
+
</tr>
|
|
284
|
+
</tfoot>
|
|
285
|
+
</table>
|
|
286
|
+
|
|
287
|
+
<h3>Fremdkapital</h3>
|
|
288
|
+
<table class="report-table">
|
|
289
|
+
<tbody>
|
|
290
|
+
${liabilityRows}
|
|
291
|
+
</tbody>
|
|
292
|
+
<tfoot>
|
|
293
|
+
<tr class="subtotal-row">
|
|
294
|
+
<td colspan="2">Summe Fremdkapital</td>
|
|
295
|
+
<td class="number">${this.formatGermanNumber(report.liabilities.totalLiabilities)}</td>
|
|
296
|
+
</tr>
|
|
297
|
+
</tfoot>
|
|
298
|
+
</table>
|
|
299
|
+
|
|
300
|
+
<table class="summary-table">
|
|
301
|
+
<tr class="total-row">
|
|
302
|
+
<td>Summe Passiva</td>
|
|
303
|
+
<td class="number">${this.formatGermanNumber(report.liabilities.totalLiabilities + report.equity.totalEquity)}</td>
|
|
304
|
+
</tr>
|
|
305
|
+
</table>
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
|
|
309
|
+
${this.generateFooter()}
|
|
310
|
+
</body>
|
|
311
|
+
</html>
|
|
312
|
+
`;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Generates comprehensive Jahresabschluss HTML
|
|
316
|
+
*/
|
|
317
|
+
generateJahresabschlussHtml(trialBalance, incomeStatement, balanceSheet) {
|
|
318
|
+
return `
|
|
319
|
+
<!DOCTYPE html>
|
|
320
|
+
<html>
|
|
321
|
+
<head>
|
|
322
|
+
<meta charset="UTF-8">
|
|
323
|
+
<style>
|
|
324
|
+
${this.getBaseStyles()}
|
|
325
|
+
.page-break { page-break-after: always; }
|
|
326
|
+
.cover-page {
|
|
327
|
+
display: flex;
|
|
328
|
+
flex-direction: column;
|
|
329
|
+
justify-content: center;
|
|
330
|
+
align-items: center;
|
|
331
|
+
height: 100vh;
|
|
332
|
+
text-align: center;
|
|
333
|
+
}
|
|
334
|
+
.cover-page h1 { font-size: 36px; margin-bottom: 20px; }
|
|
335
|
+
.cover-page h2 { font-size: 24px; margin-bottom: 40px; }
|
|
336
|
+
.toc { margin-top: 50px; }
|
|
337
|
+
.toc h2 { margin-bottom: 20px; }
|
|
338
|
+
.toc ul { list-style: none; padding: 0; }
|
|
339
|
+
.toc li { margin: 10px 0; font-size: 16px; }
|
|
340
|
+
</style>
|
|
341
|
+
</head>
|
|
342
|
+
<body>
|
|
343
|
+
<div class="cover-page">
|
|
344
|
+
<h1>Jahresabschluss</h1>
|
|
345
|
+
<h2>${this.options.companyName}</h2>
|
|
346
|
+
<p>Geschäftsjahr ${this.options.fiscalYear}</p>
|
|
347
|
+
<p>${this.formatGermanDate(this.options.dateFrom)} bis ${this.formatGermanDate(this.options.dateTo)}</p>
|
|
348
|
+
|
|
349
|
+
<div class="toc">
|
|
350
|
+
<h2>Inhalt</h2>
|
|
351
|
+
<ul>
|
|
352
|
+
<li>1. Bilanz</li>
|
|
353
|
+
<li>2. Gewinn- und Verlustrechnung</li>
|
|
354
|
+
<li>3. Summen- und Saldenliste</li>
|
|
355
|
+
</ul>
|
|
356
|
+
</div>
|
|
357
|
+
</div>
|
|
358
|
+
|
|
359
|
+
<div class="page-break"></div>
|
|
360
|
+
${this.generateBalanceSheetHtml(balanceSheet)}
|
|
361
|
+
|
|
362
|
+
<div class="page-break"></div>
|
|
363
|
+
${this.generateIncomeStatementHtml(incomeStatement)}
|
|
364
|
+
|
|
365
|
+
<div class="page-break"></div>
|
|
366
|
+
${this.generateTrialBalanceHtml(trialBalance)}
|
|
367
|
+
</body>
|
|
368
|
+
</html>
|
|
369
|
+
`;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Generates the report header
|
|
373
|
+
*/
|
|
374
|
+
generateHeader(reportTitle) {
|
|
375
|
+
return `
|
|
376
|
+
<div class="header">
|
|
377
|
+
<h1>${this.options.companyName}</h1>
|
|
378
|
+
${this.options.companyAddress ? `<p>${this.options.companyAddress}</p>` : ''}
|
|
379
|
+
${this.options.taxId ? `<p>Steuernummer: ${this.options.taxId}</p>` : ''}
|
|
380
|
+
${this.options.registrationNumber ? `<p>Handelsregister: ${this.options.registrationNumber}</p>` : ''}
|
|
381
|
+
<hr>
|
|
382
|
+
<h2>${reportTitle}</h2>
|
|
383
|
+
<p>Periode: ${this.formatGermanDate(this.options.dateFrom)} bis ${this.formatGermanDate(this.options.dateTo)}</p>
|
|
384
|
+
</div>
|
|
385
|
+
`;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Generates the report footer
|
|
389
|
+
*/
|
|
390
|
+
generateFooter() {
|
|
391
|
+
const preparedDate = this.options.preparedDate || new Date();
|
|
392
|
+
return `
|
|
393
|
+
<div class="footer">
|
|
394
|
+
<hr>
|
|
395
|
+
<p>Erstellt am: ${this.formatGermanDate(preparedDate)}</p>
|
|
396
|
+
${this.options.preparedBy ? `<p>Erstellt von: ${this.options.preparedBy}</p>` : ''}
|
|
397
|
+
<p class="disclaimer">
|
|
398
|
+
Dieser Bericht wurde automatisch generiert und ist Teil des revisionssicheren
|
|
399
|
+
Jahresabschluss-Exports gemäß GoBD.
|
|
400
|
+
</p>
|
|
401
|
+
</div>
|
|
402
|
+
`;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Gets the base CSS styles for all reports
|
|
406
|
+
*/
|
|
407
|
+
getBaseStyles() {
|
|
408
|
+
return `
|
|
409
|
+
body {
|
|
410
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
411
|
+
margin: 40px;
|
|
412
|
+
color: #333;
|
|
413
|
+
line-height: 1.6;
|
|
414
|
+
}
|
|
415
|
+
h1 { color: #2c3e50; margin-bottom: 10px; }
|
|
416
|
+
h2 { color: #34495e; margin-top: 30px; margin-bottom: 15px; }
|
|
417
|
+
h3 { color: #7f8c8d; margin-top: 20px; margin-bottom: 10px; }
|
|
418
|
+
|
|
419
|
+
.header {
|
|
420
|
+
text-align: center;
|
|
421
|
+
margin-bottom: 40px;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.footer {
|
|
425
|
+
margin-top: 50px;
|
|
426
|
+
text-align: center;
|
|
427
|
+
font-size: 12px;
|
|
428
|
+
color: #7f8c8d;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.disclaimer {
|
|
432
|
+
margin-top: 20px;
|
|
433
|
+
font-style: italic;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
table {
|
|
437
|
+
width: 100%;
|
|
438
|
+
border-collapse: collapse;
|
|
439
|
+
margin: 20px 0;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
th {
|
|
443
|
+
background-color: #34495e;
|
|
444
|
+
color: white;
|
|
445
|
+
padding: 10px;
|
|
446
|
+
text-align: left;
|
|
447
|
+
font-weight: 600;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
td {
|
|
451
|
+
padding: 8px;
|
|
452
|
+
border-bottom: 1px solid #ecf0f1;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
tbody tr:hover {
|
|
456
|
+
background-color: #f8f9fa;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.number {
|
|
460
|
+
text-align: right;
|
|
461
|
+
font-family: 'Courier New', monospace;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.total-row {
|
|
465
|
+
font-weight: bold;
|
|
466
|
+
background-color: #ecf0f1;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.subtotal-row {
|
|
470
|
+
font-weight: 600;
|
|
471
|
+
background-color: #f8f9fa;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.positive {
|
|
475
|
+
color: #27ae60;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.negative {
|
|
479
|
+
color: #e74c3c;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.result-section {
|
|
483
|
+
margin-top: 40px;
|
|
484
|
+
padding: 20px;
|
|
485
|
+
background-color: #f8f9fa;
|
|
486
|
+
border-radius: 5px;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.summary-table {
|
|
490
|
+
max-width: 500px;
|
|
491
|
+
margin: 20px auto;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.balance-sheet {
|
|
495
|
+
display: flex;
|
|
496
|
+
gap: 40px;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.aktiva, .passiva {
|
|
500
|
+
flex: 1;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
@media print {
|
|
504
|
+
body { margin: 20px; }
|
|
505
|
+
.page-break { page-break-after: always; }
|
|
506
|
+
}
|
|
507
|
+
`;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Formats number in German format (1.234,56)
|
|
511
|
+
*/
|
|
512
|
+
formatGermanNumber(value) {
|
|
513
|
+
return value.toLocaleString('de-DE', {
|
|
514
|
+
minimumFractionDigits: 2,
|
|
515
|
+
maximumFractionDigits: 2
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Formats date in German format (DD.MM.YYYY)
|
|
520
|
+
*/
|
|
521
|
+
formatGermanDate(date) {
|
|
522
|
+
return date.toLocaleDateString('de-DE', {
|
|
523
|
+
day: '2-digit',
|
|
524
|
+
month: '2-digit',
|
|
525
|
+
year: 'numeric'
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Saves a PDF report to the export directory
|
|
530
|
+
*/
|
|
531
|
+
async savePdfReport(filename, pdfBuffer) {
|
|
532
|
+
const reportsDir = path.join(this.exportPath, 'data', 'reports');
|
|
533
|
+
await plugins.smartfile.fs.ensureDir(reportsDir);
|
|
534
|
+
const filePath = path.join(reportsDir, filename);
|
|
535
|
+
await plugins.smartfile.memory.toFs(pdfBuffer, filePath);
|
|
536
|
+
return filePath;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Closes the PDF generator
|
|
540
|
+
*/
|
|
541
|
+
async close() {
|
|
542
|
+
if (this.pdfInstance) {
|
|
543
|
+
await this.pdfInstance.stop();
|
|
544
|
+
this.pdfInstance = null;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLmV4cG9ydC5wZGYuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9za3IuZXhwb3J0LnBkZi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQWU3QixNQUFNLE9BQU8sa0JBQWtCO0lBSzdCLFlBQVksVUFBa0IsRUFBRSxPQUEwQjtRQUZsRCxnQkFBVyxHQUFxQyxJQUFJLENBQUM7UUFHM0QsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFDN0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7SUFDekIsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLFVBQVU7UUFDckIsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDbkQsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxNQUEyQjtRQUM5RCxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQStCLENBQUMsQ0FBQztRQUNuRCxDQUFDO1FBRUQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ25ELE1BQU0sU0FBUyxHQUFHLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQywyQkFBMkIsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMzRSxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQyxNQUF3QjtRQUM5RCxJQUFJLENBQUMs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
|