@hartl-services/medusa-base 1.0.0 → 2.0.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/.medusa/server/src/admin/index.js +117 -1
- package/.medusa/server/src/admin/index.mjs +118 -2
- package/.medusa/server/src/documents/plugin-features.js +15 -1
- package/.medusa/server/src/documents/templates/financial-document.js +69 -51
- package/.medusa/server/src/documents/templates/format.js +44 -2
- package/.medusa/server/src/documents/templates/html-factory.js +7 -5
- package/.medusa/server/src/documents/templates/html-utils.js +12 -2
- package/.medusa/server/src/documents/templates/layout.js +115 -70
- package/.medusa/server/src/documents/templates/packing-list.js +10 -8
- package/.medusa/server/src/documents/utils/document-merchant.js +5 -5
- package/.medusa/server/src/documents/utils/document-render-settings.js +59 -0
- package/.medusa/server/src/email/application/handle-invite-event.js +8 -2
- package/.medusa/server/src/email/application/handle-password-reset-event.js +16 -4
- package/.medusa/server/src/email/domain/order-summary.js +103 -0
- package/.medusa/server/src/email/domain/refund-summary.js +43 -0
- package/.medusa/server/src/email/domain/return-summary.js +118 -0
- package/.medusa/server/src/email/domain/shipment-summary.js +74 -0
- package/.medusa/server/src/email/plugin-features.js +9 -1
- package/.medusa/server/src/email/rendering/default-templates.js +693 -65
- package/.medusa/server/src/email/rendering/load-email-shop-details.js +36 -0
- package/.medusa/server/src/email/rendering/render-email.js +16 -3
- package/.medusa/server/src/email/rendering/resolve-shop-configuration.js +20 -1
- package/.medusa/server/src/email/types/template-data.js +155 -2
- package/.medusa/server/src/modules/documents/domain/merchant.js +2 -33
- package/.medusa/server/src/modules/documents/domain/options.js +1 -7
- package/.medusa/server/src/modules/plugin-features/domain/plugin-settings.js +4 -3
- package/.medusa/server/src/public/descriptor.js +3 -1
- package/.medusa/server/src/public/shop-master-data.js +7 -7
- package/.medusa/server/src/shop-config/build-food-shop-config.js +6 -6
- package/.medusa/server/src/shop-config/options.js +5 -15
- package/.medusa/server/src/workflows/documents/issue-cancellation-after-refund.js +2 -3
- package/.medusa/server/src/workflows/documents/issue-document.js +6 -5
- package/.medusa/server/src/workflows/documents/issue-packing-list.js +9 -3
- package/.medusa/server/src/workflows/email/dispatch-email-message.js +4 -2
- package/.medusa/server/src/workflows/email/prepare-order-canceled-email.js +42 -4
- package/.medusa/server/src/workflows/email/prepare-order-received-email.js +31 -5
- package/.medusa/server/src/workflows/email/prepare-refund-email.js +25 -1
- package/.medusa/server/src/workflows/email/prepare-return-email.js +64 -3
- package/.medusa/server/src/workflows/email/prepare-shipment-email.js +36 -3
- package/README.md +180 -43
- package/dist/admin-components/features/plugin-features/components/ImageSettingInput.d.ts +15 -0
- package/dist/admin-components/features/plugin-features/components/ImageSettingInput.js +42 -0
- package/dist/admin-components/features/plugin-features/components/PluginSettingsForm.js +4 -2
- package/dist/admin-components/features/plugin-features/hooks/usePluginFeatureEnabled.d.ts +1 -1
- package/dist/admin-components/features/plugin-features/hooks/usePluginFeatures.d.ts +4 -4
- package/dist/admin-components/features/plugin-features/hooks/usePluginSettingsForm.d.ts +1 -1
- package/dist/admin-components/features/plugin-features/lib/image-upload.d.ts +6 -0
- package/dist/admin-components/features/plugin-features/lib/image-upload.js +17 -0
- package/dist/admin-components/features/plugin-features/lib/plugin-features-admin-client.d.ts +4 -4
- package/dist/admin-components/i18n/texts.d.ts +6 -0
- package/dist/admin-components/i18n/texts.js +6 -0
- package/dist/documents/templates/financial-document.d.ts +3 -3
- package/dist/documents/templates/financial-document.js +68 -50
- package/dist/documents/templates/format.d.ts +14 -0
- package/dist/documents/templates/format.js +43 -1
- package/dist/documents/templates/html-factory.d.ts +6 -2
- package/dist/documents/templates/html-factory.js +6 -4
- package/dist/documents/templates/html-utils.d.ts +6 -0
- package/dist/documents/templates/html-utils.js +11 -1
- package/dist/documents/templates/layout.d.ts +21 -3
- package/dist/documents/templates/layout.js +114 -69
- package/dist/documents/templates/packing-list.js +9 -7
- package/dist/documents/types/documents.d.ts +11 -16
- package/dist/documents/types/html-factory.d.ts +1 -0
- package/dist/email/types/shop-configuration.d.ts +25 -0
- package/dist/email/types/template-data.d.ts +509 -0
- package/dist/email/types/template-data.js +154 -1
- package/dist/modules/documents/domain/options.d.ts +1 -9
- package/dist/modules/documents/domain/options.js +0 -6
- package/dist/public/descriptor.js +2 -0
- package/dist/public/shop-master-data.d.ts +5 -6
- package/dist/public/shop-master-data.js +6 -6
- package/dist/public/types.d.ts +2 -1
- package/dist/shop-config/build-food-shop-config.js +5 -5
- package/dist/shop-config/options.d.ts +13 -8
- package/dist/shop-config/options.js +4 -14
- package/package.json +2 -2
- package/dist/modules/documents/domain/merchant.d.ts +0 -22
- package/dist/modules/documents/domain/merchant.js +0 -85
|
@@ -73,6 +73,12 @@ const texts = {
|
|
|
73
73
|
numberMax: (max) => `Höchstens ${max}.`,
|
|
74
74
|
numberRange: (min, max) => `Zwischen ${min} und ${max}.`,
|
|
75
75
|
selectPlaceholder: "Bitte auswählen",
|
|
76
|
+
imageUpload: "Bild hochladen",
|
|
77
|
+
imageReplace: "Anderes Bild hochladen",
|
|
78
|
+
imageRemove: "Entfernen",
|
|
79
|
+
imageNone: "Kein Bild hinterlegt",
|
|
80
|
+
imageUploadFailed: "Das Bild konnte nicht hochgeladen werden.",
|
|
81
|
+
imagePreviewAlt: (label) => `Vorschau ${label}`,
|
|
76
82
|
clearHint: "Ein leeres Feld speichern entfernt den gespeicherten Wert (dann gilt Konfiguration oder Standard).",
|
|
77
83
|
source: {
|
|
78
84
|
stored: "gespeichert",
|
|
@@ -383,6 +389,106 @@ function usePluginSettingsForm(plugin2) {
|
|
|
383
389
|
mutation
|
|
384
390
|
};
|
|
385
391
|
}
|
|
392
|
+
const SETTING_IMAGE_MAX_BYTES = 2 * 1024 * 1024;
|
|
393
|
+
const IMAGE_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg"]);
|
|
394
|
+
const validateSettingImage = (file) => {
|
|
395
|
+
if (!IMAGE_TYPES.has(file.type)) {
|
|
396
|
+
return "Bitte eine PNG- oder JPG-Datei auswählen.";
|
|
397
|
+
}
|
|
398
|
+
if (file.size === 0) {
|
|
399
|
+
return "Die Bilddatei ist leer.";
|
|
400
|
+
}
|
|
401
|
+
if (file.size > SETTING_IMAGE_MAX_BYTES) {
|
|
402
|
+
return "Die Bilddatei darf maximal 2 MiB groß sein.";
|
|
403
|
+
}
|
|
404
|
+
return null;
|
|
405
|
+
};
|
|
406
|
+
const ImageSettingInput = ({
|
|
407
|
+
id,
|
|
408
|
+
hintId,
|
|
409
|
+
label,
|
|
410
|
+
value,
|
|
411
|
+
disabled,
|
|
412
|
+
onChange
|
|
413
|
+
}) => {
|
|
414
|
+
const fileInput = react.useRef(null);
|
|
415
|
+
const [error, setError] = react.useState(null);
|
|
416
|
+
const upload = reactQuery.useMutation({
|
|
417
|
+
mutationFn: async (file) => {
|
|
418
|
+
const { files } = await sdk.admin.upload.create({ files: [file] });
|
|
419
|
+
const url = files[0]?.url;
|
|
420
|
+
if (!url) {
|
|
421
|
+
throw new Error("upload returned no file");
|
|
422
|
+
}
|
|
423
|
+
return url;
|
|
424
|
+
},
|
|
425
|
+
onSuccess: (url) => onChange(url),
|
|
426
|
+
onError: () => setError(texts.settings.imageUploadFailed)
|
|
427
|
+
});
|
|
428
|
+
const busy = disabled || upload.isPending;
|
|
429
|
+
const selectFile = (file) => {
|
|
430
|
+
if (!file) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
const invalid = validateSettingImage(file);
|
|
434
|
+
setError(invalid);
|
|
435
|
+
if (!invalid) {
|
|
436
|
+
upload.mutate(file);
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
|
|
440
|
+
value && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-ui-bg-subtle flex items-center justify-center rounded-md border p-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
441
|
+
"img",
|
|
442
|
+
{
|
|
443
|
+
src: value,
|
|
444
|
+
alt: texts.settings.imagePreviewAlt(label),
|
|
445
|
+
className: "max-h-24 max-w-full object-contain"
|
|
446
|
+
}
|
|
447
|
+
) }),
|
|
448
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
449
|
+
"input",
|
|
450
|
+
{
|
|
451
|
+
ref: fileInput,
|
|
452
|
+
id,
|
|
453
|
+
"aria-describedby": hintId,
|
|
454
|
+
type: "file",
|
|
455
|
+
accept: "image/png,image/jpeg",
|
|
456
|
+
className: "hidden",
|
|
457
|
+
onChange: (event) => {
|
|
458
|
+
selectFile(event.target.files?.[0]);
|
|
459
|
+
event.target.value = "";
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
),
|
|
463
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
464
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
465
|
+
ui.Button,
|
|
466
|
+
{
|
|
467
|
+
type: "button",
|
|
468
|
+
size: "small",
|
|
469
|
+
variant: "secondary",
|
|
470
|
+
isLoading: upload.isPending,
|
|
471
|
+
disabled: busy,
|
|
472
|
+
onClick: () => fileInput.current?.click(),
|
|
473
|
+
children: value ? texts.settings.imageReplace : texts.settings.imageUpload
|
|
474
|
+
}
|
|
475
|
+
),
|
|
476
|
+
value && /* @__PURE__ */ jsxRuntime.jsx(
|
|
477
|
+
ui.Button,
|
|
478
|
+
{
|
|
479
|
+
type: "button",
|
|
480
|
+
size: "small",
|
|
481
|
+
variant: "transparent",
|
|
482
|
+
disabled: busy,
|
|
483
|
+
onClick: () => onChange(""),
|
|
484
|
+
children: texts.settings.imageRemove
|
|
485
|
+
}
|
|
486
|
+
),
|
|
487
|
+
!value && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: texts.settings.imageNone })
|
|
488
|
+
] }),
|
|
489
|
+
error && /* @__PURE__ */ jsxRuntime.jsx(ui.Hint, { variant: "error", children: error })
|
|
490
|
+
] });
|
|
491
|
+
};
|
|
386
492
|
const fieldId = (pluginKey, key) => `plugin-setting-${pluginKey}-${key}`;
|
|
387
493
|
const missingLabels = (plugin2) => plugin2.missing.map(
|
|
388
494
|
(key) => plugin2.settings.find((setting) => setting.key === key)?.label ?? key
|
|
@@ -463,6 +569,16 @@ const SettingField = ({
|
|
|
463
569
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: setting.options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: option.value, children: option.label }, option.value)) })
|
|
464
570
|
]
|
|
465
571
|
}
|
|
572
|
+
) : setting.type === "image" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
573
|
+
ImageSettingInput,
|
|
574
|
+
{
|
|
575
|
+
id,
|
|
576
|
+
hintId,
|
|
577
|
+
label: setting.label,
|
|
578
|
+
value: typeof value === "string" ? value : "",
|
|
579
|
+
disabled,
|
|
580
|
+
onChange: (url) => onChange(url)
|
|
581
|
+
}
|
|
466
582
|
) : setting.type === "number" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
467
583
|
ui.Input,
|
|
468
584
|
{
|
|
@@ -502,7 +618,7 @@ const PluginSettingsForm = ({ plugin: plugin2 }) => {
|
|
|
502
618
|
const form = usePluginSettingsForm(plugin2);
|
|
503
619
|
const pending = form.mutation.isPending;
|
|
504
620
|
const hasTextFields = plugin2.settings.some(
|
|
505
|
-
(setting) => setting.type !== "boolean" && setting.type !== "secret" && setting.type !== "select"
|
|
621
|
+
(setting) => setting.type !== "boolean" && setting.type !== "secret" && setting.type !== "select" && setting.type !== "image"
|
|
506
622
|
);
|
|
507
623
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", "aria-busy": pending, children: [
|
|
508
624
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-4", children: [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useEffect, useMemo, useRef } from "react";
|
|
3
3
|
import { defineWidgetConfig, defineRouteConfig } from "@medusajs/admin-sdk";
|
|
4
|
-
import { toast,
|
|
4
|
+
import { toast, Button, Text, Hint, Container, Heading, Alert, Label, Switch, Input, Select, StatusBadge, usePrompt, FocusModal, Prompt } from "@medusajs/ui";
|
|
5
5
|
import { useQuery, useQueryClient, useMutation } from "@tanstack/react-query";
|
|
6
6
|
import { documentsPaths, packingListsPaths } from "@hartl-services/medusa-food-supplements-contracts/paths/documents";
|
|
7
7
|
import Medusa from "@medusajs/js-sdk";
|
|
@@ -70,6 +70,12 @@ const texts = {
|
|
|
70
70
|
numberMax: (max) => `Höchstens ${max}.`,
|
|
71
71
|
numberRange: (min, max) => `Zwischen ${min} und ${max}.`,
|
|
72
72
|
selectPlaceholder: "Bitte auswählen",
|
|
73
|
+
imageUpload: "Bild hochladen",
|
|
74
|
+
imageReplace: "Anderes Bild hochladen",
|
|
75
|
+
imageRemove: "Entfernen",
|
|
76
|
+
imageNone: "Kein Bild hinterlegt",
|
|
77
|
+
imageUploadFailed: "Das Bild konnte nicht hochgeladen werden.",
|
|
78
|
+
imagePreviewAlt: (label) => `Vorschau ${label}`,
|
|
73
79
|
clearHint: "Ein leeres Feld speichern entfernt den gespeicherten Wert (dann gilt Konfiguration oder Standard).",
|
|
74
80
|
source: {
|
|
75
81
|
stored: "gespeichert",
|
|
@@ -380,6 +386,106 @@ function usePluginSettingsForm(plugin2) {
|
|
|
380
386
|
mutation
|
|
381
387
|
};
|
|
382
388
|
}
|
|
389
|
+
const SETTING_IMAGE_MAX_BYTES = 2 * 1024 * 1024;
|
|
390
|
+
const IMAGE_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg"]);
|
|
391
|
+
const validateSettingImage = (file) => {
|
|
392
|
+
if (!IMAGE_TYPES.has(file.type)) {
|
|
393
|
+
return "Bitte eine PNG- oder JPG-Datei auswählen.";
|
|
394
|
+
}
|
|
395
|
+
if (file.size === 0) {
|
|
396
|
+
return "Die Bilddatei ist leer.";
|
|
397
|
+
}
|
|
398
|
+
if (file.size > SETTING_IMAGE_MAX_BYTES) {
|
|
399
|
+
return "Die Bilddatei darf maximal 2 MiB groß sein.";
|
|
400
|
+
}
|
|
401
|
+
return null;
|
|
402
|
+
};
|
|
403
|
+
const ImageSettingInput = ({
|
|
404
|
+
id,
|
|
405
|
+
hintId,
|
|
406
|
+
label,
|
|
407
|
+
value,
|
|
408
|
+
disabled,
|
|
409
|
+
onChange
|
|
410
|
+
}) => {
|
|
411
|
+
const fileInput = useRef(null);
|
|
412
|
+
const [error, setError] = useState(null);
|
|
413
|
+
const upload = useMutation({
|
|
414
|
+
mutationFn: async (file) => {
|
|
415
|
+
const { files } = await sdk.admin.upload.create({ files: [file] });
|
|
416
|
+
const url = files[0]?.url;
|
|
417
|
+
if (!url) {
|
|
418
|
+
throw new Error("upload returned no file");
|
|
419
|
+
}
|
|
420
|
+
return url;
|
|
421
|
+
},
|
|
422
|
+
onSuccess: (url) => onChange(url),
|
|
423
|
+
onError: () => setError(texts.settings.imageUploadFailed)
|
|
424
|
+
});
|
|
425
|
+
const busy = disabled || upload.isPending;
|
|
426
|
+
const selectFile = (file) => {
|
|
427
|
+
if (!file) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
const invalid = validateSettingImage(file);
|
|
431
|
+
setError(invalid);
|
|
432
|
+
if (!invalid) {
|
|
433
|
+
upload.mutate(file);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
return /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
|
|
437
|
+
value && /* @__PURE__ */ jsx("div", { className: "bg-ui-bg-subtle flex items-center justify-center rounded-md border p-4", children: /* @__PURE__ */ jsx(
|
|
438
|
+
"img",
|
|
439
|
+
{
|
|
440
|
+
src: value,
|
|
441
|
+
alt: texts.settings.imagePreviewAlt(label),
|
|
442
|
+
className: "max-h-24 max-w-full object-contain"
|
|
443
|
+
}
|
|
444
|
+
) }),
|
|
445
|
+
/* @__PURE__ */ jsx(
|
|
446
|
+
"input",
|
|
447
|
+
{
|
|
448
|
+
ref: fileInput,
|
|
449
|
+
id,
|
|
450
|
+
"aria-describedby": hintId,
|
|
451
|
+
type: "file",
|
|
452
|
+
accept: "image/png,image/jpeg",
|
|
453
|
+
className: "hidden",
|
|
454
|
+
onChange: (event) => {
|
|
455
|
+
selectFile(event.target.files?.[0]);
|
|
456
|
+
event.target.value = "";
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
),
|
|
460
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
461
|
+
/* @__PURE__ */ jsx(
|
|
462
|
+
Button,
|
|
463
|
+
{
|
|
464
|
+
type: "button",
|
|
465
|
+
size: "small",
|
|
466
|
+
variant: "secondary",
|
|
467
|
+
isLoading: upload.isPending,
|
|
468
|
+
disabled: busy,
|
|
469
|
+
onClick: () => fileInput.current?.click(),
|
|
470
|
+
children: value ? texts.settings.imageReplace : texts.settings.imageUpload
|
|
471
|
+
}
|
|
472
|
+
),
|
|
473
|
+
value && /* @__PURE__ */ jsx(
|
|
474
|
+
Button,
|
|
475
|
+
{
|
|
476
|
+
type: "button",
|
|
477
|
+
size: "small",
|
|
478
|
+
variant: "transparent",
|
|
479
|
+
disabled: busy,
|
|
480
|
+
onClick: () => onChange(""),
|
|
481
|
+
children: texts.settings.imageRemove
|
|
482
|
+
}
|
|
483
|
+
),
|
|
484
|
+
!value && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: texts.settings.imageNone })
|
|
485
|
+
] }),
|
|
486
|
+
error && /* @__PURE__ */ jsx(Hint, { variant: "error", children: error })
|
|
487
|
+
] });
|
|
488
|
+
};
|
|
383
489
|
const fieldId = (pluginKey, key) => `plugin-setting-${pluginKey}-${key}`;
|
|
384
490
|
const missingLabels = (plugin2) => plugin2.missing.map(
|
|
385
491
|
(key) => plugin2.settings.find((setting) => setting.key === key)?.label ?? key
|
|
@@ -460,6 +566,16 @@ const SettingField = ({
|
|
|
460
566
|
/* @__PURE__ */ jsx(Select.Content, { children: setting.options.map((option) => /* @__PURE__ */ jsx(Select.Item, { value: option.value, children: option.label }, option.value)) })
|
|
461
567
|
]
|
|
462
568
|
}
|
|
569
|
+
) : setting.type === "image" ? /* @__PURE__ */ jsx(
|
|
570
|
+
ImageSettingInput,
|
|
571
|
+
{
|
|
572
|
+
id,
|
|
573
|
+
hintId,
|
|
574
|
+
label: setting.label,
|
|
575
|
+
value: typeof value === "string" ? value : "",
|
|
576
|
+
disabled,
|
|
577
|
+
onChange: (url) => onChange(url)
|
|
578
|
+
}
|
|
463
579
|
) : setting.type === "number" ? /* @__PURE__ */ jsx(
|
|
464
580
|
Input,
|
|
465
581
|
{
|
|
@@ -499,7 +615,7 @@ const PluginSettingsForm = ({ plugin: plugin2 }) => {
|
|
|
499
615
|
const form = usePluginSettingsForm(plugin2);
|
|
500
616
|
const pending = form.mutation.isPending;
|
|
501
617
|
const hasTextFields = plugin2.settings.some(
|
|
502
|
-
(setting) => setting.type !== "boolean" && setting.type !== "secret" && setting.type !== "select"
|
|
618
|
+
(setting) => setting.type !== "boolean" && setting.type !== "secret" && setting.type !== "select" && setting.type !== "image"
|
|
503
619
|
);
|
|
504
620
|
return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", "aria-busy": pending, children: [
|
|
505
621
|
/* @__PURE__ */ jsxs("div", { className: "px-6 py-4", children: [
|
|
@@ -20,5 +20,19 @@ exports.documentsPluginFeatures = (0, public_1.definePluginFeatures)({
|
|
|
20
20
|
default_enabled: true,
|
|
21
21
|
},
|
|
22
22
|
],
|
|
23
|
+
settings: [
|
|
24
|
+
{
|
|
25
|
+
key: "logo",
|
|
26
|
+
label: "Logo",
|
|
27
|
+
description: "PNG oder JPG, erscheint oben links auf Rechnungen, Stornos und Packlisten. Am besten mindestens 1000 px breit, auf weißem oder transparentem Hintergrund. Ohne Logo steht dort der Firmenname.",
|
|
28
|
+
type: "image",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
key: "payment_terms",
|
|
32
|
+
label: "Zahlungskonditionen",
|
|
33
|
+
description: "Erscheint auf Rechnungen unter den Summen, z. B. „Der Betrag wurde bei der Bestellung per Kreditkarte bezahlt.“ Leer lassen, wenn nichts stehen soll. Gilt für neu erstellte und neu erzeugte Rechnungen.",
|
|
34
|
+
type: "string",
|
|
35
|
+
},
|
|
36
|
+
],
|
|
23
37
|
});
|
|
24
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
38
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLWZlYXR1cmVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2RvY3VtZW50cy9wbHVnaW4tZmVhdHVyZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsc0NBQWdEO0FBRW5DLFFBQUEsdUJBQXVCLEdBQUcsSUFBQSw2QkFBb0IsRUFBQztJQUMxRCxVQUFVLEVBQUUsV0FBVztJQUN2QixLQUFLLEVBQUUsV0FBVztJQUNsQixXQUFXLEVBQ1QscVNBQXFTO0lBQ3ZTLFFBQVEsRUFBRTtRQUNSO1lBQ0UsR0FBRyxFQUFFLFVBQVU7WUFDZixLQUFLLEVBQUUsc0JBQXNCO1lBQzdCLFdBQVcsRUFDVCxzYkFBc2I7WUFDeGIsZUFBZSxFQUFFLElBQUk7U0FDdEI7UUFDRDtZQUNFLEdBQUcsRUFBRSxlQUFlO1lBQ3BCLEtBQUssRUFBRSxZQUFZO1lBQ25CLFdBQVcsRUFDVCwyRUFBMkU7WUFDN0UsZUFBZSxFQUFFLElBQUk7U0FDdEI7S0FDRjtJQUNELFFBQVEsRUFBRTtRQUNSO1lBQ0UsR0FBRyxFQUFFLE1BQU07WUFDWCxLQUFLLEVBQUUsTUFBTTtZQUNiLFdBQVcsRUFDVCxnTUFBZ007WUFDbE0sSUFBSSxFQUFFLE9BQU87U0FDZDtRQUNEO1lBQ0UsR0FBRyxFQUFFLGVBQWU7WUFDcEIsS0FBSyxFQUFFLHFCQUFxQjtZQUM1QixXQUFXLEVBQ1QsMk1BQTJNO1lBQzdNLElBQUksRUFBRSxRQUFRO1NBQ2Y7S0FDRjtDQUNGLENBQUMsQ0FBQSJ9
|
|
@@ -3,20 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.renderFinancialDocument = void 0;
|
|
4
4
|
const format_1 = require("./format");
|
|
5
5
|
const html_utils_1 = require("./html-utils");
|
|
6
|
+
const layout_1 = require("./layout");
|
|
6
7
|
const labelsByKind = {
|
|
7
8
|
cancellation: {
|
|
8
|
-
|
|
9
|
-
recipient: "Stornorechnung an",
|
|
9
|
+
number: "Stornonummer",
|
|
10
10
|
title: "Stornorechnung",
|
|
11
11
|
},
|
|
12
12
|
credit_note: {
|
|
13
|
-
|
|
14
|
-
recipient: "Gutschrift an",
|
|
13
|
+
number: "Gutschriftnummer",
|
|
15
14
|
title: "Gutschrift",
|
|
16
15
|
},
|
|
17
16
|
invoice: {
|
|
18
|
-
|
|
19
|
-
recipient: "Rechnung an",
|
|
17
|
+
number: "Rechnungsnummer",
|
|
20
18
|
title: "Rechnung",
|
|
21
19
|
},
|
|
22
20
|
};
|
|
@@ -26,7 +24,8 @@ const renderAddress = (input) => {
|
|
|
26
24
|
return (0, html_utils_1.escapeHtml)(input.order.email);
|
|
27
25
|
}
|
|
28
26
|
return [
|
|
29
|
-
|
|
27
|
+
address.company,
|
|
28
|
+
[address.first_name, address.last_name]
|
|
30
29
|
.filter((part) => Boolean(part))
|
|
31
30
|
.join(" "),
|
|
32
31
|
address.address_1,
|
|
@@ -34,34 +33,43 @@ const renderAddress = (input) => {
|
|
|
34
33
|
[address.postal_code, address.city]
|
|
35
34
|
.filter((part) => Boolean(part))
|
|
36
35
|
.join(" "),
|
|
37
|
-
address.country_code
|
|
36
|
+
address.country_code ? (0, layout_1.formatCountryName)(address.country_code) : null,
|
|
38
37
|
]
|
|
39
38
|
.filter((part) => Boolean(part))
|
|
40
39
|
.map(html_utils_1.escapeHtml)
|
|
41
40
|
.join("<br />");
|
|
42
41
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
42
|
+
/** "Charge: L-1, MHD: 30.06.2027"; the quantity only when a line has several batches. */
|
|
43
|
+
const renderBatchDetails = (line, timeZone) => {
|
|
44
|
+
const showQuantity = line.batch_allocations.length > 1;
|
|
45
|
+
return line.batch_allocations
|
|
46
|
+
.map((allocation) => {
|
|
47
|
+
const parts = [
|
|
48
|
+
`Charge: ${allocation.lot_number}`,
|
|
49
|
+
`MHD: ${(0, format_1.formatDocumentDate)(allocation.expiry_date, timeZone)}`,
|
|
50
|
+
showQuantity ? `Menge: ${allocation.quantity}` : null,
|
|
51
|
+
].filter((part) => Boolean(part));
|
|
52
|
+
return `<div class="batch">${(0, html_utils_1.escapeHtml)(parts.join(", "))}</div>`;
|
|
53
|
+
})
|
|
47
54
|
.join("");
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
};
|
|
56
|
+
const renderLines = (input, timeZone) => input.lines
|
|
57
|
+
.map((line) => `<tr>
|
|
58
|
+
<td class="item">
|
|
59
|
+
<div class="item-title">${(0, html_utils_1.escapeHtml)(line.title)}</div>
|
|
51
60
|
${line.sku ? `<div class="sku">SKU: ${(0, html_utils_1.escapeHtml)(line.sku)}</div>` : ""}
|
|
52
|
-
${
|
|
61
|
+
${renderBatchDetails(line, timeZone)}
|
|
53
62
|
</td>
|
|
54
|
-
<td class="number">${(0, html_utils_1.escapeHtml)(line.quantity)}</td>
|
|
55
|
-
<td class="number">${(0, html_utils_1.
|
|
56
|
-
<td class="number">${(0, html_utils_1.
|
|
57
|
-
</tr
|
|
58
|
-
})
|
|
63
|
+
<td class="number quantity">${(0, html_utils_1.escapeHtml)(line.quantity)}</td>
|
|
64
|
+
<td class="number">${(0, html_utils_1.renderMoney)(line.unit_price)}</td>
|
|
65
|
+
<td class="number">${(0, html_utils_1.renderMoney)(line.total)}</td>
|
|
66
|
+
</tr>`)
|
|
59
67
|
.join("");
|
|
68
|
+
const isExemptIntraCommunitySupply = (input) => input.order.tax_compliance?.exemption_wording ===
|
|
69
|
+
"steuerfreie_innergemeinschaftliche_lieferung";
|
|
60
70
|
const renderTaxCompliance = (input) => {
|
|
61
71
|
const evidence = input.order.tax_compliance;
|
|
62
|
-
if (!evidence ||
|
|
63
|
-
evidence.exemption_wording !==
|
|
64
|
-
"steuerfreie_innergemeinschaftliche_lieferung") {
|
|
72
|
+
if (!evidence || !isExemptIntraCommunitySupply(input)) {
|
|
65
73
|
return "";
|
|
66
74
|
}
|
|
67
75
|
return `<section class="tax-compliance">
|
|
@@ -72,16 +80,18 @@ const renderTaxCompliance = (input) => {
|
|
|
72
80
|
</section>`;
|
|
73
81
|
};
|
|
74
82
|
const renderDiscountTotal = (input) => {
|
|
75
|
-
const
|
|
76
|
-
const displayAmount = input.document.kind === "invoice" && Number(amount) > 0
|
|
77
|
-
? `-${amount}`
|
|
78
|
-
: amount;
|
|
79
|
-
return (0, html_utils_1.
|
|
83
|
+
const discount = input.totals.discount_total;
|
|
84
|
+
const displayAmount = input.document.kind === "invoice" && Number(discount.amount) > 0
|
|
85
|
+
? `-${discount.amount}`
|
|
86
|
+
: discount.amount;
|
|
87
|
+
return (0, html_utils_1.renderMoney)(discount, displayAmount);
|
|
80
88
|
};
|
|
81
89
|
const formatTaxRate = (rate) => new Intl.NumberFormat(format_1.DEFAULT_FORMAT_LOCALE, {
|
|
82
90
|
maximumFractionDigits: 2,
|
|
83
91
|
style: "percent",
|
|
84
92
|
}).format(rate / 100);
|
|
93
|
+
/** One totals row below the Menge/Einzelpreis columns; the amount sits under "Summe". */
|
|
94
|
+
const renderTotalRow = (label, value, className) => `<tr${className ? ` class="${className}"` : ""}><td class="spacer"></td><td class="label" colspan="2">${(0, html_utils_1.escapeHtml)(label)}</td><td class="number">${value}</td></tr>`;
|
|
85
95
|
const renderTaxRows = (input) => {
|
|
86
96
|
const { tax_breakdown: breakdown, tax_total: taxTotal } = input.totals;
|
|
87
97
|
const rows = breakdown.length > 0
|
|
@@ -91,16 +101,17 @@ const renderTaxRows = (input) => {
|
|
|
91
101
|
}))
|
|
92
102
|
: [{ label: "Umsatzsteuer", money: taxTotal }];
|
|
93
103
|
return rows
|
|
94
|
-
.map(({ label, money }) =>
|
|
104
|
+
.map(({ label, money }) => renderTotalRow(label, (0, html_utils_1.renderMoney)(money)))
|
|
95
105
|
.join("");
|
|
96
106
|
};
|
|
107
|
+
/** Only invoices ask for payment; cancellations and credit notes do not. */
|
|
108
|
+
const renderPaymentTerms = (input) => input.document.kind === "invoice" && input.settings.payment_terms
|
|
109
|
+
? `<section class="payment-terms">${(0, html_utils_1.escapeHtml)(input.settings.payment_terms)}</section>`
|
|
110
|
+
: "";
|
|
97
111
|
const renderFinancialDocument = (input, layout, timeZone) => {
|
|
98
112
|
const labels = labelsByKind[input.document.kind];
|
|
99
113
|
const metadata = [
|
|
100
|
-
{
|
|
101
|
-
label: labels.date,
|
|
102
|
-
value: (0, format_1.formatDate)(input.document.issued_at, { timeZone }),
|
|
103
|
-
},
|
|
114
|
+
{ label: labels.number, value: input.document.number },
|
|
104
115
|
{
|
|
105
116
|
label: "Bestellung",
|
|
106
117
|
value: (0, html_utils_1.formatOrderReference)(input.order.display_id),
|
|
@@ -112,31 +123,38 @@ const renderFinancialDocument = (input, layout, timeZone) => {
|
|
|
112
123
|
value: input.document.source_document_number ?? "-",
|
|
113
124
|
});
|
|
114
125
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
if (input.order.tax_compliance && isExemptIntraCommunitySupply(input)) {
|
|
127
|
+
metadata.push({
|
|
128
|
+
label: "Kunden-UID",
|
|
129
|
+
value: input.order.tax_compliance.customer_vat_number,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
metadata.push({
|
|
133
|
+
label: "Datum",
|
|
134
|
+
value: (0, format_1.formatDocumentDate)(input.document.issued_at, timeZone),
|
|
135
|
+
});
|
|
136
|
+
const { totals } = input;
|
|
137
|
+
const body = `<table class="items financial-items">
|
|
138
|
+
<thead><tr><th class="item">Artikel</th><th class="number quantity">Menge</th><th class="number">Einzelpreis</th><th class="number">Summe</th></tr></thead>
|
|
139
|
+
<tbody class="lines">${renderLines(input, timeZone)}</tbody>
|
|
140
|
+
<tbody class="totals">
|
|
141
|
+
${renderTotalRow("Zwischensumme", (0, html_utils_1.renderMoney)(totals.subtotal))}
|
|
142
|
+
${renderTotalRow("Versand", (0, html_utils_1.renderMoney)(totals.shipping_total))}
|
|
143
|
+
${renderTotalRow("Rabatt", renderDiscountTotal(input))}
|
|
129
144
|
${renderTaxRows(input)}
|
|
130
|
-
|
|
145
|
+
${renderTotalRow("Gesamt", (0, html_utils_1.renderMoney)(totals.total), "grand-total")}
|
|
131
146
|
</tbody>
|
|
132
|
-
</table
|
|
147
|
+
</table>
|
|
148
|
+
${renderTaxCompliance(input)}
|
|
149
|
+
${renderPaymentTerms(input)}`;
|
|
133
150
|
return layout({
|
|
134
151
|
body,
|
|
135
152
|
documentTitle: labels.title,
|
|
136
153
|
metadata,
|
|
137
154
|
number: input.document.number,
|
|
138
155
|
pageTitle: labels.title,
|
|
156
|
+
recipient: renderAddress(input),
|
|
139
157
|
});
|
|
140
158
|
};
|
|
141
159
|
exports.renderFinancialDocument = renderFinancialDocument;
|
|
142
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
160
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmluYW5jaWFsLWRvY3VtZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2RvY3VtZW50cy90ZW1wbGF0ZXMvZmluYW5jaWFsLWRvY3VtZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQU1BLHFDQUFvRTtBQUNwRSw2Q0FBNEU7QUFDNUUscUNBQWlFO0FBT2pFLE1BQU0sWUFBWSxHQUFHO0lBQ25CLFlBQVksRUFBRTtRQUNaLE1BQU0sRUFBRSxjQUFjO1FBQ3RCLEtBQUssRUFBRSxnQkFBZ0I7S0FDeEI7SUFDRCxXQUFXLEVBQUU7UUFDWCxNQUFNLEVBQUUsa0JBQWtCO1FBQzFCLEtBQUssRUFBRSxZQUFZO0tBQ3BCO0lBQ0QsT0FBTyxFQUFFO1FBQ1AsTUFBTSxFQUFFLGlCQUFpQjtRQUN6QixLQUFLLEVBQUUsVUFBVTtLQUNsQjtDQUlGLENBQUE7QUFFRCxNQUFNLGFBQWEsR0FBRyxDQUFDLEtBQTRCLEVBQVUsRUFBRTtJQUM3RCxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQTtJQUMzQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDYixPQUFPLElBQUEsdUJBQVUsRUFBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFBO0lBQ3RDLENBQUM7SUFFRCxPQUFPO1FBQ0wsT0FBTyxDQUFDLE9BQU87UUFDZixDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLFNBQVMsQ0FBQzthQUNwQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQWtCLEVBQUUsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDL0MsSUFBSSxDQUFDLEdBQUcsQ0FBQztRQUNaLE9BQU8sQ0FBQyxTQUFTO1FBQ2pCLE9BQU8sQ0FBQyxTQUFTO1FBQ2pCLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxPQUFPLENBQUMsSUFBSSxDQUFDO2FBQ2hDLE1BQU0sQ0FBQyxD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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatDate = exports.formatMoney = exports.DEFAULT_FORMAT_LOCALE = void 0;
|
|
3
|
+
exports.formatDocumentDate = exports.formatMoneyParts = exports.formatDate = exports.formatMoney = exports.DEFAULT_FORMAT_LOCALE = void 0;
|
|
4
4
|
exports.DEFAULT_FORMAT_LOCALE = "de-AT";
|
|
5
5
|
const formatMoney = ({ amount, currencyCode }, { locale = exports.DEFAULT_FORMAT_LOCALE } = {}) => {
|
|
6
6
|
const numericAmount = Number(amount);
|
|
@@ -28,4 +28,46 @@ const formatDate = (value, { locale = exports.DEFAULT_FORMAT_LOCALE, options, ti
|
|
|
28
28
|
return new Intl.DateTimeFormat(locale, { timeZone, ...options }).format(date);
|
|
29
29
|
};
|
|
30
30
|
exports.formatDate = formatDate;
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* `formatMoney` split into currency and number, so a template can align the
|
|
33
|
+
* currency and the amount separately. Falls back to the whole
|
|
34
|
+
* `formatMoney` text as `amount`.
|
|
35
|
+
*/
|
|
36
|
+
const formatMoneyParts = ({ amount, currencyCode }, { locale = exports.DEFAULT_FORMAT_LOCALE } = {}) => {
|
|
37
|
+
const numericAmount = Number(amount);
|
|
38
|
+
const fallback = {
|
|
39
|
+
currency: "",
|
|
40
|
+
amount: (0, exports.formatMoney)({ amount, currencyCode }, { locale }),
|
|
41
|
+
};
|
|
42
|
+
if (!Number.isFinite(numericAmount)) {
|
|
43
|
+
return fallback;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const parts = new Intl.NumberFormat(locale, {
|
|
47
|
+
currency: currencyCode.toUpperCase(),
|
|
48
|
+
style: "currency",
|
|
49
|
+
}).formatToParts(numericAmount);
|
|
50
|
+
return {
|
|
51
|
+
currency: parts
|
|
52
|
+
.filter((part) => part.type === "currency")
|
|
53
|
+
.map((part) => part.value)
|
|
54
|
+
.join(""),
|
|
55
|
+
amount: parts
|
|
56
|
+
.filter((part) => part.type !== "currency" &&
|
|
57
|
+
!(part.type === "literal" && !part.value.trim()))
|
|
58
|
+
.map((part) => part.value)
|
|
59
|
+
.join(""),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return fallback;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
exports.formatMoneyParts = formatMoneyParts;
|
|
67
|
+
/** A document date as "01.01.2027" in the given time zone. */
|
|
68
|
+
const formatDocumentDate = (value, timeZone) => (0, exports.formatDate)(value, {
|
|
69
|
+
timeZone,
|
|
70
|
+
options: { day: "2-digit", month: "2-digit", year: "numeric" },
|
|
71
|
+
});
|
|
72
|
+
exports.formatDocumentDate = formatDocumentDate;
|
|
73
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybWF0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2RvY3VtZW50cy90ZW1wbGF0ZXMvZm9ybWF0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFhLFFBQUEscUJBQXFCLEdBQUcsT0FBTyxDQUFBO0FBV3JDLE1BQU0sV0FBVyxHQUFHLENBQ3pCLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBb0IsRUFDMUMsRUFBRSxNQUFNLEdBQUcsNkJBQXFCLEtBQXlCLEVBQUUsRUFDbkQsRUFBRTtJQUNWLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQTtJQUNwQyxNQUFNLHNCQUFzQixHQUFHLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQTtJQUN6RCxNQUFNLFFBQVEsR0FBRyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxzQkFBc0IsRUFBRSxDQUFBO0lBRTlELElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUM7UUFDcEMsT0FBTyxRQUFRLENBQUE7SUFDakIsQ0FBQztJQUVELElBQUksQ0FBQztRQUNILE9BQU8sSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRTtZQUNuQyxRQUFRLEVBQUUsc0JBQXNCO1lBQ2hDLEtBQUssRUFBRSxVQUFVO1NBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUE7SUFDMUIsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sUUFBUSxDQUFBO0lBQ2pCLENBQUM7QUFDSCxDQUFDLENBQUE7QUFwQlksUUFBQSxXQUFXLGVBb0J2QjtBQVNNLE1BQU0sVUFBVSxHQUFHLENBQ3hCLEtBQW9CLEVBQ3BCLEVBQUUsTUFBTSxHQUFHLDZCQUFxQixFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQXFCLEVBQ2hFLEVBQUU7SUFDVixNQUFNLElBQUksR0FBRyxLQUFLLFlBQVksSUFBSSxDQUFDLENB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
|