@design.estate/dees-document 1.6.9 → 2.0.2

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 (97) hide show
  1. package/dist_bundle/bundle.js +622 -605
  2. package/dist_bundle/bundle.js.map +4 -4
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/classes.pdfservice.d.ts +3 -3
  5. package/dist_ts/classes.pdfservice.js +6 -3
  6. package/dist_ts/helpers.d.ts +1 -1
  7. package/dist_ts/helpers.js +2 -2
  8. package/dist_ts/paths.js +4 -2
  9. package/dist_ts/plugins.d.ts +2 -0
  10. package/dist_ts/plugins.js +3 -1
  11. package/dist_ts_shared/demoletter.d.ts +3 -3
  12. package/dist_ts_shared/demoletter.js +223 -192
  13. package/dist_ts_shared/index.d.ts +6 -7
  14. package/dist_ts_shared/index.js +10 -8
  15. package/dist_ts_shared/interfaces/document.d.ts +15 -2
  16. package/dist_ts_shared/interfaces/document.js +1 -1
  17. package/dist_ts_shared/translation.d.ts +79 -28
  18. package/dist_ts_shared/translation.js +121 -107
  19. package/dist_ts_web/00_commitinfo_data.js +2 -2
  20. package/dist_ts_web/elements/contentinvoice.js +4 -10
  21. package/dist_ts_web/elements/document.js +8 -18
  22. package/dist_ts_web/elements/letterheader.js +5 -12
  23. package/dist_ts_web/elements/page.js +10 -22
  24. package/dist_ts_web/elements/pagecontainer.js +4 -10
  25. package/dist_ts_web/elements/pagecontent.js +5 -12
  26. package/dist_ts_web/elements/pagefooter.js +6 -14
  27. package/dist_ts_web/elements/pageheader.js +6 -14
  28. package/dist_ts_web/elements/viewer.js +3 -8
  29. package/dist_ts_web/ts_shared/translation.d.ts +82 -0
  30. package/dist_ts_web/ts_shared/translation.js +134 -0
  31. package/dist_ts_web/ts_web/00_commitinfo_data.d.ts +8 -0
  32. package/dist_ts_web/ts_web/00_commitinfo_data.js +9 -0
  33. package/dist_ts_web/ts_web/elements/contentinvoice.d.ts +41 -0
  34. package/dist_ts_web/ts_web/elements/contentinvoice.js +466 -0
  35. package/dist_ts_web/ts_web/elements/document.d.ts +27 -0
  36. package/dist_ts_web/ts_web/elements/document.demo.d.ts +1 -0
  37. package/dist_ts_web/ts_web/elements/document.demo.js +9 -0
  38. package/dist_ts_web/ts_web/elements/document.js +306 -0
  39. package/dist_ts_web/ts_web/elements/index.d.ts +10 -0
  40. package/dist_ts_web/ts_web/elements/index.js +11 -0
  41. package/dist_ts_web/ts_web/elements/letterheader.d.ts +18 -0
  42. package/dist_ts_web/ts_web/elements/letterheader.js +224 -0
  43. package/dist_ts_web/ts_web/elements/page.d.ts +25 -0
  44. package/dist_ts_web/ts_web/elements/page.js +335 -0
  45. package/dist_ts_web/ts_web/elements/pagecontainer.d.ts +14 -0
  46. package/dist_ts_web/ts_web/elements/pagecontainer.js +114 -0
  47. package/dist_ts_web/ts_web/elements/pagecontent.d.ts +19 -0
  48. package/dist_ts_web/ts_web/elements/pagecontent.js +177 -0
  49. package/dist_ts_web/ts_web/elements/pagefooter.d.ts +17 -0
  50. package/dist_ts_web/ts_web/elements/pagefooter.js +234 -0
  51. package/dist_ts_web/ts_web/elements/pageheader.d.ts +17 -0
  52. package/dist_ts_web/ts_web/elements/pageheader.js +165 -0
  53. package/dist_ts_web/ts_web/elements/paymentcode.d.ts +19 -0
  54. package/dist_ts_web/ts_web/elements/paymentcode.js +162 -0
  55. package/dist_ts_web/ts_web/elements/viewer.d.ts +15 -0
  56. package/dist_ts_web/ts_web/elements/viewer.demo.d.ts +1 -0
  57. package/dist_ts_web/ts_web/elements/viewer.demo.js +9 -0
  58. package/dist_ts_web/ts_web/elements/viewer.js +150 -0
  59. package/dist_ts_web/ts_web/index.d.ts +1 -0
  60. package/dist_ts_web/ts_web/index.js +2 -0
  61. package/dist_ts_web/ts_web/pages/index.d.ts +2 -0
  62. package/dist_ts_web/ts_web/pages/index.js +3 -0
  63. package/dist_ts_web/ts_web/pages/page1.d.ts +1 -0
  64. package/dist_ts_web/ts_web/pages/page1.js +21 -0
  65. package/dist_ts_web/ts_web/pages/page2.d.ts +1 -0
  66. package/dist_ts_web/ts_web/pages/page2.js +18 -0
  67. package/dist_ts_web/ts_web/plugins.d.ts +9 -0
  68. package/dist_ts_web/ts_web/plugins.js +14 -0
  69. package/dist_ts_web/ts_web/style.d.ts +1 -0
  70. package/dist_ts_web/ts_web/style.js +38 -0
  71. package/dist_watch/bundle.js +20421 -12784
  72. package/dist_watch/bundle.js.map +4 -4
  73. package/license +2 -2
  74. package/package.json +21 -19
  75. package/readme.hints.md +40 -1
  76. package/readme.md +202 -125
  77. package/ts/00_commitinfo_data.ts +1 -1
  78. package/ts/classes.pdfservice.ts +15 -7
  79. package/ts/helpers.ts +1 -1
  80. package/ts/paths.ts +3 -1
  81. package/ts/plugins.ts +3 -0
  82. package/ts_web/00_commitinfo_data.ts +1 -1
  83. package/ts_web/elements/contentinvoice.ts +272 -250
  84. package/ts_web/elements/document.demo.ts +7 -4
  85. package/ts_web/elements/document.ts +68 -82
  86. package/ts_web/elements/index.ts +10 -9
  87. package/ts_web/elements/letterheader.ts +106 -39
  88. package/ts_web/elements/page.ts +106 -48
  89. package/ts_web/elements/pagecontainer.ts +14 -13
  90. package/ts_web/elements/pagecontent.ts +34 -53
  91. package/ts_web/elements/pagefooter.ts +125 -45
  92. package/ts_web/elements/pageheader.ts +22 -16
  93. package/ts_web/elements/paymentcode.ts +95 -0
  94. package/ts_web/elements/viewer.demo.ts +7 -4
  95. package/ts_web/elements/viewer.ts +26 -12
  96. package/ts_web/pages/page1.ts +10 -6
  97. package/ts_web/style.ts +34 -3
@@ -9,22 +9,21 @@ import {
9
9
  customElement,
10
10
  type TemplateResult,
11
11
  css,
12
- cssManager,
13
- unsafeCSS,
14
12
  render,
15
13
  domtools,
16
- } from '@design.estate/dees-element';
17
- import * as plugins from '../plugins.js';
14
+ } from "@design.estate/dees-element";
15
+ import * as plugins from "../plugins.js";
18
16
 
19
- import { dedocumentSharedStyle } from '../style.js';
17
+ import { dedocumentSharedStyle } from "../style.js";
18
+ import type { TranslationKey } from "ts_shared/translation.js";
20
19
 
21
20
  declare global {
22
21
  interface HTMLElementTagNameMap {
23
- 'dedocument-contentinvoice': DeContentInvoice;
22
+ "dedocument-contentinvoice": DeContentInvoice;
24
23
  }
25
24
  }
26
25
 
27
- @customElement('dedocument-contentinvoice')
26
+ @customElement("dedocument-contentinvoice")
28
27
  export class DeContentInvoice extends DeesElement {
29
28
  public static demo = () => html`
30
29
  <style>
@@ -42,13 +41,13 @@ export class DeContentInvoice extends DeesElement {
42
41
  type: Object,
43
42
  reflect: true,
44
43
  })
45
- public letterData: plugins.tsclass.business.ILetter;
44
+ accessor letterData: plugins.tsclass.finance.TInvoice;
46
45
 
47
46
  @property({
48
47
  type: Object,
49
48
  reflect: true,
50
49
  })
51
- public documentSettings: plugins.shared.interfaces.IDocumentSettings;
50
+ accessor documentSettings: plugins.shared.interfaces.IDocumentSettings;
52
51
 
53
52
  constructor() {
54
53
  super();
@@ -59,15 +58,96 @@ export class DeContentInvoice extends DeesElement {
59
58
  domtools.elementBasic.staticStyles,
60
59
  dedocumentSharedStyle,
61
60
  css`
62
- :host {
63
- color: #333;
64
- }
65
-
66
61
  .trimmedContent {
67
62
  display: none;
68
63
  }
69
64
 
70
- .repeatedContent {
65
+ .grid {
66
+ display: grid;
67
+ grid-template-columns: 40px auto 50px 50px 100px 50px 100px;
68
+ }
69
+
70
+ .topLine {
71
+ margin-top: 5px;
72
+ background: #e7e7e7;
73
+ font-weight: bold;
74
+ }
75
+
76
+ .lineItem {
77
+ font-size: 12px;
78
+ padding: 5px;
79
+ border-right: 1px dashed #ccc;
80
+ white-space: nowrap;
81
+ }
82
+
83
+ .lineItem:last-child {
84
+ border-right: none;
85
+ }
86
+
87
+ .value.rightAlign,
88
+ .lineItem.rightAlign {
89
+ text-align: right;
90
+ }
91
+
92
+ .invoiceLine {
93
+ background: #ffffff00;
94
+ border-bottom: 1px dotted #ccc;
95
+ }
96
+
97
+ .invoiceLine.highlighted {
98
+ transition: background 0.2s;
99
+ background: #ffc18f;
100
+ border: 1px solid #ff9d4d;
101
+ box-sizing: content-box;
102
+ }
103
+
104
+ .sums {
105
+ margin-top: 5px;
106
+ font-size: 12px;
107
+ padding-left: 50%;
108
+ }
109
+
110
+ .sums .sumline {
111
+ margin-top: 3px;
112
+ display: grid;
113
+ grid-template-columns: auto 100px;
114
+ }
115
+
116
+ .sums .sumline .label {
117
+ padding: 2px 5px;
118
+ border-right: 1px solid #ccc;
119
+ text-align: right;
120
+ font-weight: bold;
121
+ }
122
+
123
+ .sums .sumline .value {
124
+ padding: 2px 5px;
125
+ }
126
+
127
+ .sums .sumline .value--total {
128
+ font-weight: bold;
129
+ }
130
+
131
+ .divider {
132
+ margin-top: 8px;
133
+ border-top: 1px dotted #ccc;
134
+ }
135
+
136
+ .taxNote {
137
+ font-size: 12px;
138
+ padding: 4px;
139
+ background: #eeeeeb;
140
+ text-align: center;
141
+ }
142
+
143
+ .infoBox {
144
+ margin-top: 22px;
145
+ line-height: 1.4em;
146
+ }
147
+
148
+ .infoBox .label {
149
+ padding-bottom: 2px;
150
+ font-weight: bold;
71
151
  }
72
152
  `,
73
153
  ];
@@ -80,6 +160,17 @@ export class DeContentInvoice extends DeesElement {
80
160
  `;
81
161
  }
82
162
 
163
+ protected formatPrice(
164
+ value: number,
165
+ currency = "EUR",
166
+ lang = "de-DE"
167
+ ): string {
168
+ return new Intl.NumberFormat(lang, {
169
+ style: "currency",
170
+ currency,
171
+ }).format(value);
172
+ }
173
+
83
174
  public getTotalNet = (): number => {
84
175
  let totalNet = 0;
85
176
 
@@ -87,7 +178,7 @@ export class DeContentInvoice extends DeesElement {
87
178
  return totalNet;
88
179
  }
89
180
 
90
- for (const item of this.letterData.content.invoiceData.items) {
181
+ for (const item of this.letterData.items) {
91
182
  totalNet += item.unitNetPrice * item.unitQuantity;
92
183
  }
93
184
  return totalNet;
@@ -109,7 +200,7 @@ export class DeContentInvoice extends DeesElement {
109
200
  public getVatGroups = () => {
110
201
  const vatGroups: {
111
202
  vatPercentage: number;
112
- items: plugins.tsclass.finance.IInvoice['items'];
203
+ items: plugins.tsclass.finance.TInvoice["items"];
113
204
  vatAmountSum: number;
114
205
  }[] = [];
115
206
 
@@ -118,17 +209,22 @@ export class DeContentInvoice extends DeesElement {
118
209
  }
119
210
 
120
211
  const taxAmounts: number[] = [];
121
- for (const item of this.letterData.content.invoiceData.items) {
122
- taxAmounts.includes(item.vatPercentage) ? null : taxAmounts.push(item.vatPercentage);
212
+ for (const item of this.letterData.items) {
213
+ taxAmounts.includes(item.vatPercentage)
214
+ ? null
215
+ : taxAmounts.push(item.vatPercentage);
123
216
  }
124
217
 
125
218
  for (const taxAmount of taxAmounts) {
126
- const matchingItems = this.letterData.content.invoiceData.items.filter(
219
+ const matchingItems = this.letterData.items.filter(
127
220
  (itemArg) => itemArg.vatPercentage === taxAmount
128
221
  );
129
222
  let sum = 0;
130
223
  for (const matchingItem of matchingItems) {
131
- sum += matchingItem.unitNetPrice * matchingItem.unitQuantity * (taxAmount / 100);
224
+ sum +=
225
+ matchingItem.unitNetPrice *
226
+ matchingItem.unitQuantity *
227
+ (taxAmount / 100);
132
228
  }
133
229
  vatGroups.push({
134
230
  items: matchingItems,
@@ -136,15 +232,21 @@ export class DeContentInvoice extends DeesElement {
136
232
  vatAmountSum: Math.round(sum * 100) / 100,
137
233
  });
138
234
  }
139
- return vatGroups;
235
+ return vatGroups.sort((a, b) => b.vatPercentage - a.vatPercentage);
140
236
  };
141
237
 
142
238
  public async getContentNodes() {
143
239
  await this.elementDomReady;
144
240
  return {
145
- currentContent: this.shadowRoot.querySelector('.currentContent') as HTMLElement,
146
- trimmedContent: this.shadowRoot.querySelector('.trimmedContent') as HTMLElement,
147
- repeatedContent: this.shadowRoot.querySelector('.repeatedContent') as HTMLElement,
241
+ currentContent: this.shadowRoot.querySelector(
242
+ ".currentContent"
243
+ ) as HTMLElement,
244
+ trimmedContent: this.shadowRoot.querySelector(
245
+ ".trimmedContent"
246
+ ) as HTMLElement,
247
+ repeatedContent: this.shadowRoot.querySelector(
248
+ ".repeatedContent"
249
+ ) as HTMLElement,
148
250
  };
149
251
  }
150
252
 
@@ -156,7 +258,7 @@ export class DeContentInvoice extends DeesElement {
156
258
  public async trimEndByOne() {
157
259
  await this.elementDomReady;
158
260
  this.shadowRoot
159
- .querySelector('.trimmedContent')
261
+ .querySelector(".trimmedContent")
160
262
  .append(
161
263
  (await this.getContentNodes()).currentContent.children.item(
162
264
  (await this.getContentNodes()).currentContent.children.length - 1
@@ -166,7 +268,8 @@ export class DeContentInvoice extends DeesElement {
166
268
 
167
269
  public async trimStartToOffset(contentOffsetArg: number) {
168
270
  await this.elementDomReady;
169
- const beginningLength = (await this.getContentNodes()).currentContent.children.length;
271
+ const beginningLength = (await this.getContentNodes()).currentContent
272
+ .children.length;
170
273
  while (
171
274
  (await this.getContentNodes()).currentContent.children.length !==
172
275
  beginningLength - contentOffsetArg
@@ -178,13 +281,13 @@ export class DeContentInvoice extends DeesElement {
178
281
  if (
179
282
  (await this.getContentNodes()).currentContent.children
180
283
  .item(0)
181
- .classList.contains('needsDataHeader')
284
+ .classList.contains("needsDataHeader")
182
285
  ) {
183
286
  const trimmedContent = (await this.getContentNodes()).trimmedContent;
184
287
  let startPoint = trimmedContent.children.length;
185
288
  while (startPoint > 0) {
186
289
  const element = trimmedContent.children.item(startPoint - 1);
187
- if (element.classList.contains('dataHeader')) {
290
+ if (element.classList.contains("dataHeader")) {
188
291
  (await this.getContentNodes()).repeatedContent.append(element);
189
292
  break;
190
293
  }
@@ -193,275 +296,194 @@ export class DeContentInvoice extends DeesElement {
193
296
  }
194
297
  }
195
298
 
196
- public async firstUpdated(_changedProperties: Map<string | number | symbol, unknown>) {
299
+ public translateKey(key: TranslationKey): string {
300
+ return plugins.shared.translation.translate(
301
+ this.documentSettings.languageCode,
302
+ key
303
+ );
304
+ }
305
+
306
+ public async firstUpdated(
307
+ _changedProperties: Map<string | number | symbol, unknown>
308
+ ) {
197
309
  super.firstUpdated(_changedProperties);
198
310
  this.attachInvoiceDom();
199
311
  }
200
312
 
313
+ private renderPaymentTerms(): TemplateResult {
314
+ return html`<div class="infoBox">
315
+ <div>
316
+ <div>
317
+ <div class="label">
318
+ ${this.translateKey("invoice@@payment.terms")}
319
+ </div>
320
+ <span>
321
+ ${this.translateKey("invoice@@payment.terms.direct")}
322
+ ${new Intl.DateTimeFormat(this.documentSettings.languageCode, {
323
+ dateStyle: this.documentSettings.dateStyle,
324
+ }).format(
325
+ new Date(this.letterData.date).setDate(
326
+ new Date(this.letterData.date).getDate() +
327
+ this.letterData?.dueInDays
328
+ )
329
+ )}
330
+ </span>
331
+ </div>
332
+ </div>
333
+ </div>`;
334
+ }
335
+
336
+ private renderPaymentInfo(): TemplateResult {
337
+ const bic = this.letterData?.from.sepaConnection.bic;
338
+ const name = this.letterData?.from.name;
339
+ const iban = this.letterData?.from.sepaConnection.iban;
340
+ const currency = this.letterData?.currency;
341
+ const totalGross = this.getTotalGross();
342
+ const reference = this.letterData?.id;
343
+
344
+ return html`<div class="infoBox">
345
+ <div>
346
+ <div>
347
+ <div class="label">${this.translateKey("invoice@@payment.qr")}</div>
348
+ <span> ${this.translateKey("invoice@@payment.qr.description")} </span>
349
+ </div>
350
+ <dedocument-paymentcode
351
+ bic="${bic}"
352
+ name="${name}"
353
+ iban="${iban}"
354
+ currency="${currency}"
355
+ totalGross="${totalGross}"
356
+ reference="${reference}"
357
+ />
358
+ </div>
359
+ </div>`;
360
+ }
361
+
362
+ private renderReferencedContract(): TemplateResult {
363
+ return null;
364
+ // return this.documentSettings.enableInvoiceContractRefSection &&
365
+ // this.invoiceData?.content?.contractData?.contractDate
366
+ // ? html`
367
+ // <div class="infoBox">
368
+ // <div class="label">
369
+ // ${this.translateKey("invoice@@referencedContract")}
370
+ // </div>
371
+ // ${this.translateKey("invoice@@referencedContract.text")}
372
+ // ${new Intl.DateTimeFormat(this.documentSettings.languageCode, {
373
+ // dateStyle: this.documentSettings.dateStyle,
374
+ // }).format(
375
+ // new Date(this.invoiceData?.content.contractData.contractDate)
376
+ // )}.
377
+ // </div>
378
+ // `
379
+ // : null;
380
+ }
381
+
201
382
  public async attachInvoiceDom() {
202
383
  const contentNodes = await this.getContentNodes();
203
384
  render(
204
385
  html`
205
- <style>
206
- .grid {
207
- display: grid;
208
- grid-template-columns: 40px auto 60px 60px 84px 84px 46px;
209
- }
210
- .topLine {
211
- margin-top: 5px;
212
- background: #e7e7e7;
213
- font-weight: bold;
214
- }
215
- .lineItem {
216
- font-size: 12px;
217
- padding: 5px;
218
- border-right: 1px dashed #ccc;
219
- }
220
-
221
- .lineItem:last-child {
222
- border-right: none;
223
- }
224
-
225
- .lineItem.rightAlign {
226
- text-align: right;
227
- }
228
-
229
- .invoiceLine {
230
- background: #ffffff00;
231
- border-bottom: 1px dotted #ccc;
232
- }
233
-
234
- .invoiceLine.highlighted {
235
- transition: background 0.2s;
236
- background: #ffc18f;
237
- border: 1px solid #ff9d4d;
238
- box-sizing: content-box;
239
- }
240
-
241
- .sums {
242
- margin-top: 5px;
243
- font-size: 12px;
244
- padding-left: 50%;
245
- }
246
-
247
- .sums .sumline {
248
- margin-top: 3px;
249
- display: grid;
250
- grid-template-columns: auto 90px;
251
- }
252
-
253
- .sums .sumline .label {
254
- padding: 2px 5px;
255
- border-right: 1px solid #ccc;
256
- text-align: right;
257
- font-weight: bold;
258
- }
259
-
260
- .sums .sumline .value {
261
- padding: 2px 5px;
262
- font-weight: bold;
263
- }
264
-
265
- .divider {
266
- margin-top: 8px;
267
- border-top: 1px dotted #ccc;
268
- }
269
-
270
- .taxNote {
271
- font-size: 12px;
272
- padding: 4px;
273
- background: #eeeeeb;
274
- text-align: center;
275
- }
276
-
277
- .infoBox {
278
- border-radius: 7px;
279
- border: 1px solid #ddd;
280
- border-left: 3px solid #c5e1a5;
281
- padding: 8px;
282
- margin-top: 16px;
283
- line-height: 1.4em;
284
- font-size: 16px;
285
- }
286
-
287
- .infoBox .label {
288
- padding-bottom: 2px;
289
- font-size: 12px;
290
- font-weight: bold;
291
- }
292
-
293
- .paymentCode {
294
- text-align: center;
295
- border-left: 2px solid #666;
296
- }
297
- </style>
298
- <div>We hereby invoice products and services provided to you by Lossless GmbH:</div>
386
+ <div>${this.translateKey("invoice@@introStatement")}</div>
299
387
  <div class="grid topLine dataHeader">
300
388
  <div class="lineItem rightAlign">
301
- ${plugins.shared.translation.translate(
302
- this.documentSettings.languageCode,
303
- 'itemPos',
304
- 'Item Pos.'
305
- )}
389
+ ${this.translateKey("invoice@@item.position")}
306
390
  </div>
307
391
  <div class="lineItem">
308
- ${plugins.shared.translation.translate(
309
- this.documentSettings.languageCode,
310
- 'description',
311
- 'Description'
312
- )}
392
+ ${this.translateKey("invoice@@description")}
313
393
  </div>
314
394
  <div class="lineItem rightAlign">
315
- ${plugins.shared.translation.translate(
316
- this.documentSettings.languageCode,
317
- 'quantity',
318
- 'Quantity'
319
- )}
320
- </div>
321
- <div class="lineItem">
322
- ${plugins.shared.translation.translate(
323
- this.documentSettings.languageCode,
324
- 'unitType',
325
- 'Unit Type'
326
- )}
395
+ ${this.translateKey("invoice@@quantity")}
327
396
  </div>
397
+ <div class="lineItem">${this.translateKey("invoice@@unit.type")}</div>
328
398
  <div class="lineItem rightAlign">
329
- ${plugins.shared.translation.translate(
330
- this.documentSettings.languageCode,
331
- 'unitNetPrice',
332
- 'Unit Net Price'
333
- )}
399
+ ${this.translateKey("invoice@@price.unit.net")}
334
400
  </div>
335
401
  <div class="lineItem rightAlign">
336
- ${plugins.shared.translation.translate(
337
- this.documentSettings.languageCode,
338
- 'totalNetPrice',
339
- 'Total Net Price'
340
- )}
402
+ ${this.translateKey("invoice@@vat.short")}
341
403
  </div>
342
404
  <div class="lineItem rightAlign">
343
- ${plugins.shared.translation.translate(
344
- this.documentSettings.languageCode,
345
- 'vatShort',
346
- 'VAT'
347
- )}
405
+ ${this.translateKey("invoice@@price.total.net")}
348
406
  </div>
349
407
  </div>
350
- ${(() => {
351
- let counter = 1;
352
- return this.letterData?.content.invoiceData?.items?.map((invoiceItem) => {
353
- const isHighlighted = false; // TODO: implement rest of highlight logic
354
- return html`
355
- <div class="grid invoiceLine needsDataHeader ${isHighlighted ? 'highlighted' : ''}">
356
- <div class="lineItem rightAlign">${counter++}</div>
357
- <div class="lineItem">${invoiceItem.name}</div>
358
- <div class="lineItem rightAlign">${invoiceItem.unitQuantity}</div>
359
- <div class="lineItem">${invoiceItem.unitType}</div>
360
- <div class="lineItem rightAlign">
361
- ${invoiceItem.unitNetPrice} ${this.letterData?.content.invoiceData.currency}
362
- </div>
363
- <div class="lineItem rightAlign">
364
- ${invoiceItem.unitQuantity * invoiceItem.unitNetPrice}
365
- ${this.letterData?.content.invoiceData.currency}
366
- </div>
367
- <div class="lineItem rightAlign">${invoiceItem.vatPercentage}%</div>
408
+ ${this.letterData?.items?.map(
409
+ (invoiceItem, index) => html`
410
+ <div class="grid needsDataHeader">
411
+ <div class="lineItem rightAlign">${index + 1}</div>
412
+ <div class="lineItem">${invoiceItem.name}</div>
413
+ <div class="lineItem rightAlign">${invoiceItem.unitQuantity}</div>
414
+ <div class="lineItem">${invoiceItem.unitType}</div>
415
+ <div class="lineItem rightAlign">
416
+ ${this.formatPrice(invoiceItem.unitNetPrice)}
368
417
  </div>
369
- `;
370
- });
371
- })()}
418
+ <div class="lineItem rightAlign">
419
+ ${invoiceItem.vatPercentage}%
420
+ </div>
421
+ <div class="lineItem rightAlign">
422
+ ${this.formatPrice(
423
+ invoiceItem.unitQuantity * invoiceItem.unitNetPrice
424
+ )}
425
+ </div>
426
+ </div>
427
+ `
428
+ )}
372
429
  <div class="sums">
373
430
  <div class="sumline">
374
- <div class="label">Total net</div>
375
- <div class="value">${this.getTotalNet()} EUR</div>
431
+ <div class="label">
432
+ ${this.translateKey("invoice@@sum.total.net")}
433
+ </div>
434
+ <div class="value value--total rightAlign">
435
+ ${this.formatPrice(this.getTotalNet())}
436
+ </div>
376
437
  </div>
377
438
  ${this.getVatGroups().map((vatGroupArg) => {
378
- let itemNumbers = '';
379
- let first = true;
380
- for (const item of vatGroupArg.items) {
381
- const itemIndex = this.letterData.content.invoiceData.items.indexOf(item);
382
- itemNumbers += `${first ? '' : ', '}${itemIndex + 1}`;
383
- first = false;
384
- }
439
+ let itemNumbers = vatGroupArg.items
440
+ .map((item) => this.letterData.items.indexOf(item) + 1)
441
+ .join(", ");
385
442
  return html`
386
443
  <div class="sumline">
387
444
  <div class="label">
388
- Vat ${vatGroupArg.vatPercentage}%
445
+ ${this.translateKey("vat.short")}
446
+ ${vatGroupArg.vatPercentage}%
389
447
  ${this.documentSettings.vatGroupPositions
390
448
  ? html`
391
449
  <br /><span style="font-weight: normal"
392
- >(on item positions: ${itemNumbers})</span
450
+ >(${this.translateKey("invoice@@vat.position")}:
451
+ ${itemNumbers})</span
393
452
  >
394
453
  `
395
454
  : html``}
396
455
  </div>
397
- <div class="value">${vatGroupArg.vatAmountSum} EUR</div>
456
+ <div class="value rightAlign">
457
+ ${this.formatPrice(vatGroupArg.vatAmountSum)}
458
+ </div>
398
459
  </div>
399
460
  `;
400
461
  })}
401
462
  <div class="sumline">
402
- <div class="label">Total gross</div>
403
- <div class="value">${this.getTotalGross()} EUR</div>
463
+ <div class="label">${this.translateKey("invoice@@totalGross")}</div>
464
+ <div class="value value--total rightAlign">
465
+ ${this.formatPrice(this.getTotalGross())}
466
+ </div>
404
467
  </div>
405
468
  </div>
406
469
  <div class="divider"></div>
407
- ${this.letterData?.content.invoiceData.reverseCharge
408
- ? html`
409
- <div class="taxNote">
410
- ${plugins.shared.translation.translate(
411
- this.documentSettings.languageCode,
412
- 'reverseVatNote',
413
- 'VAT arises on a reverse charge basis and is payable by the customer.'
414
- )}
415
- </div>
416
- `
470
+
471
+ ${this.letterData?.reverseCharge
472
+ ? html`<div class="taxNote">
473
+ ${this.translateKey("invoice@@vat.reverseCharge.note")}
474
+ </div>`
417
475
  : ``}
418
- <div class="infoBox">
419
- <div class="label">Payment Terms:</div>
420
- Payment is due within 30 days starting from the reception of this invoice. Please use the
421
- following SEPA details:
422
- <br /><br />
423
- Beneficiary: ${this.letterData?.from.name}<br />
424
- IBAN: ${this.letterData?.from?.sepaConnection?.iban}<br />
425
- BIC: ${this.letterData?.from?.sepaConnection?.bic}<br />
426
- Description: ${this.letterData?.content.invoiceData?.id}<br />
427
- Amount: ${this.getTotalGross()} ${this.letterData?.content.invoiceData.currency}
428
- </div>
429
- ${this.letterData?.content?.contractData?.contractDate
430
- ? html`
431
- <div class="infoBox">
432
- <div class="label">Referenced contract:</div>
433
- This invoice is adhering to agreements made by contract between the parties on
434
- ${plugins.smarttime.ExtendedDate.fromMillis(
435
- this.letterData?.content.contractData.contractDate
436
- ).format('MMMM D, YYYY')}.
437
- </div>
438
- `
439
- : html``}
440
- <div class="infoBox paymentCode">
441
- <div class="label">Sepa Payment Code:</div>
442
- </div>
476
+
477
+ <!-- REFERENCED CONTRACT -->
478
+ ${this.renderReferencedContract()}
479
+
480
+ <!-- PAYMENT TERMS -->
481
+ ${this.renderPaymentTerms()}
482
+
483
+ <!-- PAYMENT INFO -->
484
+ ${this.renderPaymentInfo()}
443
485
  `,
444
486
  contentNodes.currentContent
445
487
  );
446
- const canvas = document.createElement('canvas');
447
- plugins.qrcode.toCanvas(
448
- canvas,
449
- `BCD
450
- 001
451
- 1
452
- SCT
453
- ${this.letterData.content.invoiceData.billedBy.sepaConnection.bic}
454
- ${this.letterData.content.invoiceData.billedBy.name}
455
- ${this.letterData.content.invoiceData.billedBy.sepaConnection.iban}
456
- EUR${this.getTotalGross()}
457
- CHAR
458
- ${this.letterData.content.invoiceData.id}
459
- ${this.letterData.content.invoiceData.id}
460
- EPC QR Code`,
461
- (error) => {
462
- if (error) console.error(error);
463
- }
464
- );
465
- contentNodes.currentContent.querySelector('.paymentCode').append(canvas);
466
488
  }
467
489
  }