@fin.cx/skr 1.1.0 → 1.2.1

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.
Files changed (64) hide show
  1. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  2. package/dist_ts/00_commitinfo_data.js +9 -0
  3. package/dist_ts/index.d.ts +6 -0
  4. package/dist_ts/index.js +7 -1
  5. package/dist_ts/plugins.d.ts +8 -1
  6. package/dist_ts/plugins.js +10 -2
  7. package/dist_ts/skr.api.d.ts +70 -0
  8. package/dist_ts/skr.api.js +348 -1
  9. package/dist_ts/skr.classes.account.d.ts +28 -0
  10. package/dist_ts/skr.classes.account.js +87 -4
  11. package/dist_ts/skr.classes.journalentry.js +56 -4
  12. package/dist_ts/skr.classes.ledger.js +5 -1
  13. package/dist_ts/skr.export.accounts.d.ts +53 -0
  14. package/dist_ts/skr.export.accounts.js +111 -0
  15. package/dist_ts/skr.export.balances.d.ts +59 -0
  16. package/dist_ts/skr.export.balances.js +205 -0
  17. package/dist_ts/skr.export.d.ts +110 -0
  18. package/dist_ts/skr.export.js +315 -0
  19. package/dist_ts/skr.export.ledger.d.ts +95 -0
  20. package/dist_ts/skr.export.ledger.js +164 -0
  21. package/dist_ts/skr.export.pdf.d.ts +82 -0
  22. package/dist_ts/skr.export.pdf.js +548 -0
  23. package/dist_ts/skr.invoice.adapter.d.ts +98 -0
  24. package/dist_ts/skr.invoice.adapter.js +476 -0
  25. package/dist_ts/skr.invoice.booking.d.ts +102 -0
  26. package/dist_ts/skr.invoice.booking.js +578 -0
  27. package/dist_ts/skr.invoice.entity.d.ts +287 -0
  28. package/dist_ts/skr.invoice.entity.js +2 -0
  29. package/dist_ts/skr.invoice.mapper.d.ts +69 -0
  30. package/dist_ts/skr.invoice.mapper.js +401 -0
  31. package/dist_ts/skr.invoice.storage.d.ts +140 -0
  32. package/dist_ts/skr.invoice.storage.js +529 -0
  33. package/dist_ts/skr.postingkeys.d.ts +56 -0
  34. package/dist_ts/skr.postingkeys.js +196 -0
  35. package/dist_ts/skr.security.d.ts +65 -0
  36. package/dist_ts/skr.security.js +319 -0
  37. package/dist_ts/skr.types.d.ts +19 -0
  38. package/dist_ts/skr03.data.js +3 -1
  39. package/dist_ts/skr04.data.js +3 -1
  40. package/package.json +17 -12
  41. package/readme.hints.md +54 -1
  42. package/readme.md +207 -16
  43. package/ts/00_commitinfo_data.ts +8 -0
  44. package/ts/index.ts +6 -0
  45. package/ts/plugins.ts +22 -1
  46. package/ts/skr.api.ts +485 -0
  47. package/ts/skr.classes.account.ts +106 -3
  48. package/ts/skr.classes.journalentry.ts +78 -3
  49. package/ts/skr.classes.ledger.ts +4 -0
  50. package/ts/skr.export.accounts.ts +154 -0
  51. package/ts/skr.export.balances.ts +270 -0
  52. package/ts/skr.export.ledger.ts +249 -0
  53. package/ts/skr.export.pdf.ts +601 -0
  54. package/ts/skr.export.ts +443 -0
  55. package/ts/skr.invoice.adapter.ts +581 -0
  56. package/ts/skr.invoice.booking.ts +760 -0
  57. package/ts/skr.invoice.entity.ts +351 -0
  58. package/ts/skr.invoice.mapper.ts +486 -0
  59. package/ts/skr.invoice.storage.ts +710 -0
  60. package/ts/skr.postingkeys.ts +252 -0
  61. package/ts/skr.security.ts +405 -0
  62. package/ts/skr.types.ts +27 -0
  63. package/ts/skr03.data.ts +2 -0
  64. package/ts/skr04.data.ts +2 -0
@@ -0,0 +1,578 @@
1
+ import * as plugins from './plugins.js';
2
+ import { JournalEntry } from './skr.classes.journalentry.js';
3
+ import { SKRInvoiceMapper } from './skr.invoice.mapper.js';
4
+ import { suggestPostingKey } from './skr.postingkeys.js';
5
+ /**
6
+ * Automatic booking engine for invoices
7
+ * Creates journal entries from invoice data based on SKR mapping rules
8
+ */
9
+ export class InvoiceBookingEngine {
10
+ constructor(skrType) {
11
+ this.skrType = skrType;
12
+ this.mapper = new SKRInvoiceMapper(skrType);
13
+ this.logger = new plugins.smartlog.ConsoleLog();
14
+ }
15
+ /**
16
+ * Book an invoice to the ledger
17
+ */
18
+ async bookInvoice(invoice, bookingRules, options) {
19
+ try {
20
+ // Get complete booking rules
21
+ const rules = this.mapper.mapInvoiceToSKR(invoice, bookingRules);
22
+ // Calculate confidence
23
+ const confidence = this.mapper.calculateConfidence(invoice, rules);
24
+ // Check if auto-booking is allowed
25
+ if (options?.autoBook && confidence < (options.confidenceThreshold || 80)) {
26
+ return {
27
+ success: false,
28
+ confidence,
29
+ warnings: [`Confidence score ${confidence}% is below threshold ${options.confidenceThreshold || 80}%`]
30
+ };
31
+ }
32
+ // Validate invoice before booking
33
+ if (!options?.skipValidation) {
34
+ const validationErrors = this.validateInvoice(invoice);
35
+ if (validationErrors.length > 0) {
36
+ return {
37
+ success: false,
38
+ confidence,
39
+ errors: validationErrors
40
+ };
41
+ }
42
+ }
43
+ // Build journal entry
44
+ const journalEntry = await this.buildJournalEntry(invoice, rules, options);
45
+ // Create booking info
46
+ const bookingInfo = {
47
+ journalEntryId: journalEntry.id,
48
+ transactionIds: journalEntry.transactionIds || [],
49
+ bookedAt: new Date(),
50
+ bookedBy: 'system',
51
+ bookingRules: {
52
+ vendorAccount: rules.vendorControlAccount,
53
+ customerAccount: rules.customerControlAccount,
54
+ expenseAccounts: this.getUsedExpenseAccounts(invoice, rules),
55
+ revenueAccounts: this.getUsedRevenueAccounts(invoice, rules),
56
+ vatAccounts: this.getUsedVATAccounts(invoice, rules)
57
+ },
58
+ confidence,
59
+ autoBooked: options?.autoBook || false
60
+ };
61
+ // Post the journal entry
62
+ // TODO: When MongoDB transactions are available, wrap this in a transaction
63
+ // Example: await db.withTransaction(async (session) => { ... })
64
+ try {
65
+ await journalEntry.validate();
66
+ await journalEntry.post();
67
+ // Mark invoice as posted if we have a reference to it
68
+ if (invoice.status !== 'posted') {
69
+ invoice.status = 'posted';
70
+ }
71
+ }
72
+ catch (postError) {
73
+ this.logger.log('error', `Failed to post journal entry: ${postError}`);
74
+ throw postError; // Re-throw to trigger rollback when transactions are available
75
+ }
76
+ return {
77
+ success: true,
78
+ journalEntry,
79
+ bookingInfo,
80
+ confidence,
81
+ warnings: this.generateWarnings(invoice, rules)
82
+ };
83
+ }
84
+ catch (error) {
85
+ this.logger.log('error', `Failed to book invoice: ${error}`);
86
+ return {
87
+ success: false,
88
+ confidence: 0,
89
+ errors: [`Booking failed: ${error.message}`]
90
+ };
91
+ }
92
+ }
93
+ /**
94
+ * Build journal entry from invoice
95
+ */
96
+ async buildJournalEntry(invoice, rules, options) {
97
+ const lines = [];
98
+ const isInbound = invoice.direction === 'inbound';
99
+ const isCredit = invoice.invoiceTypeCode === '381'; // Credit note
100
+ // Determine if we need to reverse the normal booking direction
101
+ const reverseDirection = isCredit;
102
+ if (isInbound) {
103
+ // Inbound invoice (AP)
104
+ lines.push(...this.buildAPEntry(invoice, rules, reverseDirection));
105
+ }
106
+ else {
107
+ // Outbound invoice (AR)
108
+ lines.push(...this.buildAREntry(invoice, rules, reverseDirection));
109
+ }
110
+ // Create journal entry
111
+ const journalData = {
112
+ date: options?.bookingDate || invoice.issueDate,
113
+ description: this.buildDescription(invoice),
114
+ reference: options?.bookingReference || invoice.invoiceNumber,
115
+ lines,
116
+ skrType: this.skrType
117
+ };
118
+ const journalEntry = new JournalEntry(journalData);
119
+ return journalEntry;
120
+ }
121
+ /**
122
+ * Build AP (Accounts Payable) journal entry lines
123
+ */
124
+ buildAPEntry(invoice, rules, reverseDirection) {
125
+ const lines = [];
126
+ // Group lines by account
127
+ const accountGroups = this.groupLinesByAccount(invoice, rules);
128
+ // Create expense/asset entries
129
+ for (const [accountNumber, group] of Object.entries(accountGroups)) {
130
+ const amount = group.reduce((sum, line) => sum + line.netAmount, 0);
131
+ if (reverseDirection) {
132
+ // Credit note: credit expense account
133
+ lines.push({
134
+ accountNumber,
135
+ credit: Math.abs(amount),
136
+ description: this.getAccountDescription(accountNumber, group),
137
+ postingKey: 9 // 19% input VAT for expenses
138
+ });
139
+ }
140
+ else {
141
+ // Regular invoice: debit expense account
142
+ lines.push({
143
+ accountNumber,
144
+ debit: Math.abs(amount),
145
+ description: this.getAccountDescription(accountNumber, group),
146
+ postingKey: 9 // 19% input VAT for expenses
147
+ });
148
+ }
149
+ }
150
+ // Create VAT entries
151
+ const vatLines = this.buildVATLines(invoice, rules, 'input', reverseDirection);
152
+ lines.push(...vatLines);
153
+ // Create vendor control account entry
154
+ const controlAccount = this.mapper.getControlAccount(invoice, rules);
155
+ const totalAmount = Math.abs(invoice.payableAmount);
156
+ if (reverseDirection) {
157
+ // Credit note: debit vendor account
158
+ lines.push({
159
+ accountNumber: controlAccount,
160
+ debit: totalAmount,
161
+ description: `${invoice.supplier.name} - Credit Note ${invoice.invoiceNumber}`,
162
+ postingKey: 40 // Tax-free for control account
163
+ });
164
+ }
165
+ else {
166
+ // Regular invoice: credit vendor account
167
+ lines.push({
168
+ accountNumber: controlAccount,
169
+ credit: totalAmount,
170
+ description: `${invoice.supplier.name} - Invoice ${invoice.invoiceNumber}`,
171
+ postingKey: 40 // Tax-free for control account
172
+ });
173
+ }
174
+ return lines;
175
+ }
176
+ /**
177
+ * Build AR (Accounts Receivable) journal entry lines
178
+ */
179
+ buildAREntry(invoice, rules, reverseDirection) {
180
+ const lines = [];
181
+ // Group lines by account
182
+ const accountGroups = this.groupLinesByAccount(invoice, rules);
183
+ // Create revenue entries
184
+ for (const [accountNumber, group] of Object.entries(accountGroups)) {
185
+ const amount = group.reduce((sum, line) => sum + line.netAmount, 0);
186
+ if (reverseDirection) {
187
+ // Credit note: debit revenue account
188
+ lines.push({
189
+ accountNumber,
190
+ debit: Math.abs(amount),
191
+ description: this.getAccountDescription(accountNumber, group),
192
+ postingKey: 9 // 19% output VAT for revenue
193
+ });
194
+ }
195
+ else {
196
+ // Regular invoice: credit revenue account
197
+ lines.push({
198
+ accountNumber,
199
+ credit: Math.abs(amount),
200
+ description: this.getAccountDescription(accountNumber, group),
201
+ postingKey: 9 // 19% output VAT for revenue
202
+ });
203
+ }
204
+ }
205
+ // Create VAT entries
206
+ const vatLines = this.buildVATLines(invoice, rules, 'output', reverseDirection);
207
+ lines.push(...vatLines);
208
+ // Create customer control account entry
209
+ const controlAccount = this.mapper.getControlAccount(invoice, rules);
210
+ const totalAmount = Math.abs(invoice.payableAmount);
211
+ if (reverseDirection) {
212
+ // Credit note: credit customer account
213
+ lines.push({
214
+ accountNumber: controlAccount,
215
+ credit: totalAmount,
216
+ description: `${invoice.customer.name} - Credit Note ${invoice.invoiceNumber}`,
217
+ postingKey: 40 // Tax-free for control account
218
+ });
219
+ }
220
+ else {
221
+ // Regular invoice: debit customer account
222
+ lines.push({
223
+ accountNumber: controlAccount,
224
+ debit: totalAmount,
225
+ description: `${invoice.customer.name} - Invoice ${invoice.invoiceNumber}`,
226
+ postingKey: 40 // Tax-free for control account
227
+ });
228
+ }
229
+ return lines;
230
+ }
231
+ /**
232
+ * Build VAT lines
233
+ */
234
+ buildVATLines(invoice, rules, direction, reverseDirection) {
235
+ const lines = [];
236
+ const taxScenario = invoice.taxScenario || 'domestic_taxed';
237
+ // Handle reverse charge specially
238
+ if (taxScenario === 'reverse_charge') {
239
+ return this.buildReverseChargeVATLines(invoice, rules);
240
+ }
241
+ // Standard VAT booking
242
+ for (const vatBreak of invoice.vatBreakdown) {
243
+ if (vatBreak.taxAmount === 0)
244
+ continue;
245
+ const vatAccount = this.mapper.getVATAccount(vatBreak.vatCategory, direction, taxScenario);
246
+ const amount = Math.abs(vatBreak.taxAmount);
247
+ const description = `VAT ${vatBreak.vatCategory.rate}%`;
248
+ const vatRate = vatBreak.vatCategory.rate;
249
+ // Select posting key based on VAT rate: 8 for 7%, 9 for 19%
250
+ const postingKey = vatRate === 7 ? 8 : 9;
251
+ if (direction === 'input') {
252
+ // Input VAT (Vorsteuer)
253
+ if (reverseDirection) {
254
+ lines.push({ accountNumber: vatAccount, credit: amount, description, postingKey });
255
+ }
256
+ else {
257
+ lines.push({ accountNumber: vatAccount, debit: amount, description, postingKey });
258
+ }
259
+ }
260
+ else {
261
+ // Output VAT (Umsatzsteuer)
262
+ if (reverseDirection) {
263
+ lines.push({ accountNumber: vatAccount, debit: amount, description, postingKey });
264
+ }
265
+ else {
266
+ lines.push({ accountNumber: vatAccount, credit: amount, description, postingKey });
267
+ }
268
+ }
269
+ }
270
+ return lines;
271
+ }
272
+ /**
273
+ * Calculate VAT amount from taxable amount and rate
274
+ */
275
+ calculateVAT(taxableAmount, rate) {
276
+ return Math.round(taxableAmount * rate / 100 * 100) / 100; // Round to 2 decimals
277
+ }
278
+ /**
279
+ * Calculate effective VAT rate for the invoice (weighted average)
280
+ */
281
+ calculateEffectiveVATRate(invoice) {
282
+ const totalTaxable = invoice.vatBreakdown.reduce((sum, vb) => sum + vb.taxableAmount, 0);
283
+ if (totalTaxable === 0) {
284
+ return 19; // Default to standard German VAT rate
285
+ }
286
+ // Calculate weighted average VAT rate
287
+ const weightedRate = invoice.vatBreakdown.reduce((sum, vb) => {
288
+ return sum + (vb.vatCategory.rate * vb.taxableAmount);
289
+ }, 0);
290
+ return Math.round(weightedRate / totalTaxable * 100) / 100;
291
+ }
292
+ /**
293
+ * Build reverse charge VAT lines (§13b UStG)
294
+ */
295
+ buildReverseChargeVATLines(invoice, rules) {
296
+ const lines = [];
297
+ // For reverse charge, we book both input and output VAT
298
+ for (const vatBreak of invoice.vatBreakdown) {
299
+ // For reverse charge, calculate VAT if not provided
300
+ const amount = vatBreak.taxAmount > 0
301
+ ? Math.abs(vatBreak.taxAmount)
302
+ : this.calculateVAT(Math.abs(vatBreak.taxableAmount), vatBreak.vatCategory.rate);
303
+ // Input VAT (deductible)
304
+ const inputVATAccount = this.mapper.getVATAccount(vatBreak.vatCategory, 'input', 'reverse_charge');
305
+ // Output VAT (payable)
306
+ const outputVATAccount = this.mapper.getVATAccount(vatBreak.vatCategory, 'output', 'reverse_charge');
307
+ lines.push({
308
+ accountNumber: inputVATAccount,
309
+ debit: amount,
310
+ description: `Reverse charge input VAT ${vatBreak.vatCategory.rate}%`,
311
+ postingKey: 94 // Reverse charge posting key
312
+ }, {
313
+ accountNumber: outputVATAccount,
314
+ credit: amount,
315
+ description: `Reverse charge output VAT ${vatBreak.vatCategory.rate}%`,
316
+ postingKey: 94 // Reverse charge posting key
317
+ });
318
+ }
319
+ return lines;
320
+ }
321
+ /**
322
+ * Group invoice lines by account
323
+ */
324
+ groupLinesByAccount(invoice, rules) {
325
+ const groups = {};
326
+ for (const line of invoice.lines) {
327
+ const account = this.mapper.mapInvoiceLineToAccount(line, invoice, rules);
328
+ if (!groups[account]) {
329
+ groups[account] = [];
330
+ }
331
+ groups[account].push(line);
332
+ }
333
+ return groups;
334
+ }
335
+ /**
336
+ * Book payment for an invoice
337
+ */
338
+ async bookPayment(invoice, payment, rules) {
339
+ try {
340
+ const lines = [];
341
+ const isInbound = invoice.direction === 'inbound';
342
+ const controlAccount = this.mapper.getControlAccount(invoice, rules);
343
+ // Check for skonto
344
+ const skontoAmount = payment.skontoTaken || 0;
345
+ const paymentAmount = payment.amount;
346
+ const fullAmount = paymentAmount + skontoAmount;
347
+ if (isInbound) {
348
+ // Payment for vendor invoice
349
+ lines.push({
350
+ accountNumber: controlAccount,
351
+ debit: fullAmount,
352
+ description: `Payment to ${invoice.supplier.name}`,
353
+ postingKey: 3 // Payment with VAT
354
+ }, {
355
+ accountNumber: '1000', // Bank account (would be configurable)
356
+ credit: paymentAmount,
357
+ description: `Bank payment ${payment.endToEndId || payment.paymentId}`,
358
+ postingKey: 40 // Tax-free for bank account
359
+ });
360
+ // Book skonto if taken
361
+ if (skontoAmount > 0) {
362
+ const skontoAccounts = this.mapper.getSkontoAccounts(invoice);
363
+ lines.push({
364
+ accountNumber: skontoAccounts.skontoAccount,
365
+ credit: skontoAmount,
366
+ description: `Skonto received`,
367
+ postingKey: 40 // Tax-free for skonto
368
+ });
369
+ // VAT correction for skonto
370
+ if (rules.skontoMethod === 'gross') {
371
+ const effectiveRate = this.calculateEffectiveVATRate(invoice);
372
+ const vatCorrection = Math.round(skontoAmount * effectiveRate / (100 + effectiveRate) * 100) / 100;
373
+ lines.push({
374
+ accountNumber: skontoAccounts.vatCorrectionAccount,
375
+ credit: vatCorrection,
376
+ description: `Skonto VAT correction`,
377
+ postingKey: 40 // Tax-free for correction
378
+ });
379
+ }
380
+ }
381
+ }
382
+ else {
383
+ // Payment from customer
384
+ lines.push({
385
+ accountNumber: '1000', // Bank account
386
+ debit: paymentAmount,
387
+ description: `Payment from ${invoice.customer.name}`,
388
+ postingKey: 40 // Tax-free for bank account
389
+ }, {
390
+ accountNumber: controlAccount,
391
+ credit: fullAmount,
392
+ description: `Customer payment ${payment.endToEndId || payment.paymentId}`,
393
+ postingKey: 3 // Payment with VAT
394
+ });
395
+ // Book skonto if granted
396
+ if (skontoAmount > 0) {
397
+ const skontoAccounts = this.mapper.getSkontoAccounts(invoice);
398
+ lines.push({
399
+ accountNumber: skontoAccounts.skontoAccount,
400
+ debit: skontoAmount,
401
+ description: `Skonto granted`,
402
+ postingKey: 40 // Tax-free for skonto
403
+ });
404
+ // VAT correction for skonto
405
+ if (rules.skontoMethod === 'gross') {
406
+ const effectiveRate = this.calculateEffectiveVATRate(invoice);
407
+ const vatCorrection = Math.round(skontoAmount * effectiveRate / (100 + effectiveRate) * 100) / 100;
408
+ lines.push({
409
+ accountNumber: skontoAccounts.vatCorrectionAccount,
410
+ debit: vatCorrection,
411
+ description: `Skonto VAT correction`,
412
+ postingKey: 40 // Tax-free for correction
413
+ });
414
+ }
415
+ }
416
+ }
417
+ // Create journal entry for payment
418
+ const journalData = {
419
+ date: payment.paymentDate,
420
+ description: `Payment for invoice ${invoice.invoiceNumber}`,
421
+ reference: payment.endToEndId || payment.remittanceInfo || payment.paymentId,
422
+ lines,
423
+ skrType: this.skrType
424
+ };
425
+ const journalEntry = new JournalEntry(journalData);
426
+ await journalEntry.validate();
427
+ await journalEntry.post();
428
+ return {
429
+ success: true,
430
+ journalEntry,
431
+ confidence: 100
432
+ };
433
+ }
434
+ catch (error) {
435
+ this.logger.log('error', `Failed to book payment: ${error}`);
436
+ return {
437
+ success: false,
438
+ confidence: 0,
439
+ errors: [`Payment booking failed: ${error.message}`]
440
+ };
441
+ }
442
+ }
443
+ /**
444
+ * Validate invoice before booking
445
+ */
446
+ validateInvoice(invoice) {
447
+ const errors = [];
448
+ // Check required fields
449
+ if (!invoice.invoiceNumber) {
450
+ errors.push('Invoice number is required');
451
+ }
452
+ if (!invoice.issueDate) {
453
+ errors.push('Issue date is required');
454
+ }
455
+ if (!invoice.supplier || !invoice.supplier.name) {
456
+ errors.push('Supplier information is required');
457
+ }
458
+ if (!invoice.customer || !invoice.customer.name) {
459
+ errors.push('Customer information is required');
460
+ }
461
+ if (invoice.lines.length === 0) {
462
+ errors.push('Invoice must have at least one line item');
463
+ }
464
+ // Validate amounts
465
+ const calculatedNet = invoice.lines.reduce((sum, line) => sum + line.netAmount, 0);
466
+ const tolerance = 0.01;
467
+ if (Math.abs(calculatedNet - invoice.lineNetAmount) > tolerance) {
468
+ errors.push(`Line net amount mismatch: calculated ${calculatedNet}, stated ${invoice.lineNetAmount}`);
469
+ }
470
+ // Validate VAT
471
+ const calculatedVAT = invoice.vatBreakdown.reduce((sum, vb) => sum + vb.taxAmount, 0);
472
+ if (Math.abs(calculatedVAT - invoice.totalVATAmount) > tolerance) {
473
+ errors.push(`VAT amount mismatch: calculated ${calculatedVAT}, stated ${invoice.totalVATAmount}`);
474
+ }
475
+ // Validate total
476
+ const calculatedTotal = invoice.taxExclusiveAmount + invoice.totalVATAmount;
477
+ if (Math.abs(calculatedTotal - invoice.taxInclusiveAmount) > tolerance) {
478
+ errors.push(`Total amount mismatch: calculated ${calculatedTotal}, stated ${invoice.taxInclusiveAmount}`);
479
+ }
480
+ return errors;
481
+ }
482
+ /**
483
+ * Generate warnings for the booking
484
+ */
485
+ generateWarnings(invoice, rules) {
486
+ const warnings = [];
487
+ // Warn about default account usage
488
+ const hasDefaultAccounts = invoice.lines.some(line => !line.accountNumber && !line.productCode);
489
+ if (hasDefaultAccounts) {
490
+ warnings.push('Some lines are using default expense/revenue accounts');
491
+ }
492
+ // Warn about mixed VAT rates
493
+ if (invoice.vatBreakdown.length > 1) {
494
+ warnings.push('Invoice contains mixed VAT rates');
495
+ }
496
+ // Warn about reverse charge
497
+ if (invoice.taxScenario === 'reverse_charge') {
498
+ warnings.push('Reverse charge procedure applied - verify VAT treatment');
499
+ }
500
+ // Warn about credit notes
501
+ if (invoice.invoiceTypeCode === '381') {
502
+ warnings.push('This is a credit note - amounts will be reversed');
503
+ }
504
+ // Warn about foreign currency
505
+ if (invoice.currencyCode !== 'EUR') {
506
+ warnings.push(`Invoice is in foreign currency: ${invoice.currencyCode}`);
507
+ }
508
+ return warnings;
509
+ }
510
+ /**
511
+ * Build description for journal entry
512
+ */
513
+ buildDescription(invoice) {
514
+ const type = invoice.invoiceTypeCode === '381' ? 'Credit Note' : 'Invoice';
515
+ const party = invoice.direction === 'inbound'
516
+ ? invoice.supplier.name
517
+ : invoice.customer.name;
518
+ return `${type} ${invoice.invoiceNumber} - ${party}`;
519
+ }
520
+ /**
521
+ * Get account description for a group of lines
522
+ */
523
+ getAccountDescription(accountNumber, lines) {
524
+ if (lines.length === 1) {
525
+ return lines[0].description;
526
+ }
527
+ return `${this.mapper.getAccountDescription(accountNumber)} (${lines.length} items)`;
528
+ }
529
+ /**
530
+ * Get used expense accounts
531
+ */
532
+ getUsedExpenseAccounts(invoice, rules) {
533
+ if (invoice.direction !== 'inbound')
534
+ return [];
535
+ const accounts = new Set();
536
+ for (const line of invoice.lines) {
537
+ const account = this.mapper.mapInvoiceLineToAccount(line, invoice, rules);
538
+ accounts.add(account);
539
+ }
540
+ return Array.from(accounts);
541
+ }
542
+ /**
543
+ * Get used revenue accounts
544
+ */
545
+ getUsedRevenueAccounts(invoice, rules) {
546
+ if (invoice.direction !== 'outbound')
547
+ return [];
548
+ const accounts = new Set();
549
+ for (const line of invoice.lines) {
550
+ const account = this.mapper.mapInvoiceLineToAccount(line, invoice, rules);
551
+ accounts.add(account);
552
+ }
553
+ return Array.from(accounts);
554
+ }
555
+ /**
556
+ * Get used VAT accounts
557
+ */
558
+ getUsedVATAccounts(invoice, rules) {
559
+ const accounts = new Set();
560
+ const direction = invoice.direction === 'inbound' ? 'input' : 'output';
561
+ const taxScenario = invoice.taxScenario || 'domestic_taxed';
562
+ for (const vatBreak of invoice.vatBreakdown) {
563
+ const account = this.mapper.getVATAccount(vatBreak.vatCategory, direction, taxScenario);
564
+ accounts.add(account);
565
+ }
566
+ // Add reverse charge accounts if applicable
567
+ if (taxScenario === 'reverse_charge') {
568
+ for (const vatBreak of invoice.vatBreakdown) {
569
+ const inputAccount = this.mapper.getVATAccount(vatBreak.vatCategory, 'input', 'reverse_charge');
570
+ const outputAccount = this.mapper.getVATAccount(vatBreak.vatCategory, 'output', 'reverse_charge');
571
+ accounts.add(inputAccount);
572
+ accounts.add(outputAccount);
573
+ }
574
+ }
575
+ return Array.from(accounts);
576
+ }
577
+ }
578
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLmludm9pY2UuYm9va2luZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3Nrci5pbnZvaWNlLmJvb2tpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzdELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzNELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBa0N6RDs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sb0JBQW9CO0lBSy9CLFlBQVksT0FBaUI7UUFDM0IsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFDdkIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzVDLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBQ2xELENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxXQUFXLENBQ3RCLE9BQWlCLEVBQ2pCLFlBQXFDLEVBQ3JDLE9BQXlCO1FBRXpCLElBQUksQ0FBQztZQUNILDZCQUE2QjtZQUM3QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxPQUFPLEVBQUUsWUFBWSxDQUFDLENBQUM7WUFFakUsdUJBQXVCO1lBQ3ZCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBRW5FLG1DQUFtQztZQUNuQyxJQUFJLE9BQU8sRUFBRSxRQUFRLElBQUksVUFBVSxHQUFHLENBQUMsT0FBTyxDQUFDLG1CQUFtQixJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUM7Z0JBQzFFLE9BQU87b0JBQ0ws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