@hartl-services/medusa-base 2.9.0 → 2.11.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 +5 -1
- package/.medusa/server/src/admin/index.mjs +5 -1
- package/.medusa/server/src/documents/templates/financial-document.js +23 -4
- package/.medusa/server/src/email/application/deliver-ephemeral-auth-mail.js +2 -4
- package/.medusa/server/src/email/application/handle-password-reset-event.js +75 -27
- package/.medusa/server/src/email/rendering/default-templates.js +2 -1
- package/.medusa/server/src/email/rendering/render-email.js +2 -1
- package/.medusa/server/src/email/rendering/resolve-shop-configuration.js +5 -1
- package/.medusa/server/src/email/templates/blocks/dynamic-blocks.js +5 -2
- package/.medusa/server/src/email/templates/defaults/documents.js +8 -1
- package/.medusa/server/src/email/templates/defaults/subjects.js +3 -1
- package/.medusa/server/src/email/templates/defaults/texts.js +4 -2
- package/.medusa/server/src/email/templates/render.js +2 -1
- package/.medusa/server/src/email/templates/sample-data.js +5 -1
- package/.medusa/server/src/email/types/email-kinds.js +3 -1
- package/.medusa/server/src/email/types/template-data.js +8 -1
- package/.medusa/server/src/modules/documents/domain/cancellation-snapshot.js +4 -1
- package/.medusa/server/src/modules/documents/domain/tax-breakdown.js +103 -29
- package/.medusa/server/src/modules/email/migrations/Migration20261013120000.js +20 -0
- package/.medusa/server/src/shared/lib/index.js +2 -1
- package/.medusa/server/src/shared/lib/shipping-tax.js +12 -0
- package/.medusa/server/src/shop-config/build-food-shop-config.js +7 -1
- package/.medusa/server/src/workflows/documents/issue-invoice-after-shipment.js +44 -33
- package/README.md +43 -9
- package/dist/documents/templates/financial-document.js +22 -3
- package/dist/documents/types/documents.d.ts +13 -0
- package/dist/email/types/email-kinds.d.ts +3 -2
- package/dist/email/types/email-kinds.js +2 -0
- package/dist/email/types/shop-configuration.d.ts +8 -0
- package/dist/email/types/template-data.d.ts +6 -1
- package/dist/email/types/template-data.js +7 -0
- package/dist/shared/lib/index.d.ts +1 -0
- package/dist/shared/lib/index.js +1 -0
- package/dist/shared/lib/shipping-tax.d.ts +8 -0
- package/dist/shared/lib/shipping-tax.js +11 -0
- package/dist/shop-config/build-food-shop-config.js +6 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1436,6 +1436,11 @@ Options of the `email` namespace:
|
|
|
1436
1436
|
`orderNotificationEmail` mailbox. `verifyAccountUrl` (optional builder,
|
|
1437
1437
|
like `passwordResetUrl`; the mail appends `#token=`) is the storefront page
|
|
1438
1438
|
that confirms an account, needed while `customer_verification` is on.
|
|
1439
|
+
`adminPasswordResetUrl` (optional builder, receives `{ token }`) is the
|
|
1440
|
+
Medusa Admin's "choose a new password" page; without it an Admin user's
|
|
1441
|
+
password reset fails with `render_failed`. `buildFoodShopConfig` sets
|
|
1442
|
+
`<MEDUSA_BACKEND_URL>/app/reset-password?token=<token>` (the dashboard reads
|
|
1443
|
+
the token from the query).
|
|
1439
1444
|
`adminAffiliateApplicationsUrl` (optional builder, receives
|
|
1440
1445
|
`{ applicationId }`) is the Admin page of the partner applications; the
|
|
1441
1446
|
notification about a new application shows its "Im Admin prüfen" button
|
|
@@ -1539,7 +1544,7 @@ feature is switched on again.
|
|
|
1539
1544
|
| --------------------- | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- |
|
|
1540
1545
|
| (plugin switch) | E-Mail | on | every route under `/admin/email/*` (mail log, resends, attachments; 404); jobs `email-reconcile-attempts`, `email-reconcile-pending-messages`, `email-retry-messages`; every feature below | checkout and orders; already queued messages stay stored |
|
|
1541
1546
|
| `order_mails` | Bestell-Mails | on | subscribers `order-placed`, `email-shipment-created`, `email-order-canceled`, `return-requested`, `return-received`, `documents-shipment-invoice-assignment-decided`, `documents-order-cancellation-ready`, `documents-refund-ready`; route `/admin/draft-orders/:id/order-confirmation` (404) and its draft-order widget | jobs, Admin routes, already created messages |
|
|
1542
|
-
| `account_mails` | Konto-Mails | on | subscribers `password-reset
|
|
1547
|
+
| `account_mails` | Konto-Mails | on | subscribers `password-reset` (customers and Admin users), `user-invite`, `customer-verification` (the last one only with `customer_verification` on as well); not the login code mail, which depends on neither this feature nor the plugin switch (see "Kunden-Login") | jobs, Admin routes, already created messages |
|
|
1543
1548
|
| `customer_verification` | Kontobestätigung per E-Mail | off | Medusa's e-mail verification of customer logins (see "Kontobestätigung per E-Mail"), route `POST /store/customer-verification/resend` (404 while off), subscriber `customer-verification`; child of `account_mails` | checkout and orders; confirmed accounts stay confirmed, already created messages |
|
|
1544
1549
|
| `affiliate_reminders` | Affiliate-Mails | on | subscribers `affiliate-consignment-reminder-due` (reminders to affiliates) and `affiliate-application-submitted` (notification to the shop about a new partner application) | jobs, Admin routes, already created messages |
|
|
1545
1550
|
|
|
@@ -1826,9 +1831,10 @@ has at most 35 characters. Email runtime-validates every contract before use.
|
|
|
1826
1831
|
|
|
1827
1832
|
- The accepted kinds are exactly `order.received`, `order.received.admin`, `order.shipped`,
|
|
1828
1833
|
`order.canceled`, `order.return_requested`, `order.return_received`,
|
|
1829
|
-
`order.refunded`, `auth.password_reset`, `auth.
|
|
1830
|
-
`auth.login_code`, `affiliate.consignment_report_due`,
|
|
1831
|
-
`affiliate.application_submitted.admin
|
|
1834
|
+
`order.refunded`, `auth.password_reset`, `auth.admin_password_reset`,
|
|
1835
|
+
`auth.verification`, `auth.login_code`, `affiliate.consignment_report_due`,
|
|
1836
|
+
`affiliate.application_submitted.admin`, `user.invite` and
|
|
1837
|
+
`system.credential_expiry.admin`.
|
|
1832
1838
|
- Every automatic message has a deterministic business key.
|
|
1833
1839
|
- Every placed Order creates independent customer and Shop intents. The customer
|
|
1834
1840
|
intent honors `no_notification`; the Shop intent always targets the static
|
|
@@ -1914,7 +1920,7 @@ an info box lists number, customer, e-mail and order time, followed by an
|
|
|
1914
1920
|
button is left out without it) and `timeZone` (IANA; the order time is left
|
|
1915
1921
|
out without it). `buildFoodShopConfig` sets both (`<MEDUSA_BACKEND_URL>/app/
|
|
1916
1922
|
orders/<id>` and its `timeZone` option). The layout receives `audience`
|
|
1917
|
-
(`"shop"` for this kind, `affiliate.application_submitted.admin` and `
|
|
1923
|
+
(`"shop"` for this kind, `affiliate.application_submitted.admin`, `system.credential_expiry.admin`, `user.invite` and `auth.admin_password_reset`, `"customer"` for all others) and
|
|
1918
1924
|
shows the contact line only to customers.
|
|
1919
1925
|
|
|
1920
1926
|
The shipping confirmation (`order.shipped`, one per fulfillment) receives a
|
|
@@ -1978,6 +1984,20 @@ without `iat`) and a note that the mail can be ignored. The lifetime is
|
|
|
1978
1984
|
passed as the ephemeral `valid_minutes` next to `reset_url` and is never
|
|
1979
1985
|
persisted.
|
|
1980
1986
|
|
|
1987
|
+
The same Medusa event with `actor_type: "user"` (the Admin's "Passwort
|
|
1988
|
+
zurücksetzen" at `/app/reset-password`) becomes its own kind,
|
|
1989
|
+
`auth.admin_password_reset`, with its own Admin template: subject "Neues
|
|
1990
|
+
Passwort für den Admin-Bereich von <displayName>", the same button, link text,
|
|
1991
|
+
lifetime and ignore note, and the link from `adminPasswordResetUrl` (the token
|
|
1992
|
+
in the query). It is sent only when exactly one Admin user has the address:
|
|
1993
|
+
the `emailpass` identity is shared by all actor types, so a customer could ask
|
|
1994
|
+
for an Admin reset of their own identity, and that request is ignored
|
|
1995
|
+
(`no_admin_user`). A token whose `actor_type` differs from the event's is
|
|
1996
|
+
ignored as `invalid_token`; every other actor type stays `invalid_event`. Like
|
|
1997
|
+
the customer reset it is gated by `account_mails`, ephemeral (never resent or
|
|
1998
|
+
retried by the generic job) and stored with `resource_type` `"user"`; its
|
|
1999
|
+
layout audience is `"shop"`.
|
|
2000
|
+
|
|
1981
2001
|
The account confirmation (`auth.verification`) has the subject "Bestätige
|
|
1982
2002
|
deine E-Mail-Adresse", a "E-Mail-Adresse bestätigen" button, the link as
|
|
1983
2003
|
copyable text, a note that the link is only valid for a limited time (a new
|
|
@@ -2374,10 +2394,24 @@ separate documents package since 1.0.0.
|
|
|
2374
2394
|
persists the customer company, customer UID and exemption wording in that
|
|
2375
2395
|
same snapshot. B2C and non-eligible evidence add no tax-proof statement.
|
|
2376
2396
|
- Freezes a tax breakdown (`totals.tax_breakdown`) grouped by the order's
|
|
2377
|
-
item
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2397
|
+
item tax-line name and rate, as configured on the Medusa tax region, with
|
|
2398
|
+
the tax and the net amount (`taxable_amount`, after discounts) per rate.
|
|
2399
|
+
Shipping follows the items: a shipping tax line with the code
|
|
2400
|
+
`APPORTIONED_SHIPPING_TAX_CODE` (`/lib`; Tax Compliance's "Anteilige
|
|
2401
|
+
Versandsteuer") is split back onto the item rates by the items' net
|
|
2402
|
+
amount after discounts, the key Tax Compliance weights it by, so the
|
|
2403
|
+
invoice never prints a weighted rate. Other shipping tax joins the items'
|
|
2404
|
+
row when the cart has one item rate equal to it, otherwise it keeps its
|
|
2405
|
+
own row.
|
|
2406
|
+
Amounts are rounded to the currency and add up exactly to the tax total;
|
|
2407
|
+
cancellations scale them proportionally. Snapshots issued before these
|
|
2408
|
+
fields existed read as an empty breakdown or without net amounts.
|
|
2409
|
+
- Prints net amounts before discounts: line unit price and "Summe",
|
|
2410
|
+
"Zwischensumme" (items), "Versand" (before a free-shipping promotion),
|
|
2411
|
+
then all promotions as one net "Rabatt" (only when there is a discount),
|
|
2412
|
+
the tax rows and the gross "Gesamt"; the rows add up to the total. With
|
|
2413
|
+
several tax rates each tax row also names its net amount ("AT Reduziert
|
|
2414
|
+
10 % auf € 55,00").
|
|
2381
2415
|
- Persists one immutable decision per shipped Fulfillment. A leased, Order-
|
|
2382
2416
|
unique coordinator chooses exactly one invoice carrier without assuming
|
|
2383
2417
|
event delivery order; all other shipments become `non_carrier`.
|
|
@@ -63,7 +63,7 @@ const renderLines = (input, timeZone) => input.lines
|
|
|
63
63
|
</td>
|
|
64
64
|
<td class="number quantity">${(0, lib_1.escapeHtml)(line.quantity)}</td>
|
|
65
65
|
<td class="number">${(0, html_utils_1.renderMoney)(line.unit_price)}</td>
|
|
66
|
-
<td class="number">${(0, html_utils_1.renderMoney)(line.
|
|
66
|
+
<td class="number">${(0, html_utils_1.renderMoney)(line.subtotal)}</td>
|
|
67
67
|
</tr>`)
|
|
68
68
|
.join("");
|
|
69
69
|
const isExemptIntraCommunitySupply = (input) => input.order.tax_compliance?.exemption_wording ===
|
|
@@ -93,11 +93,30 @@ const formatTaxRate = (rate) => new Intl.NumberFormat(format_1.DEFAULT_FORMAT_LO
|
|
|
93
93
|
}).format(rate / 100);
|
|
94
94
|
/** One totals row below the Menge/Einzelpreis columns; the amount sits under "Summe". */
|
|
95
95
|
const renderTotalRow = (label, value, className) => `<tr${className ? ` class="${className}"` : ""}><td class="spacer"></td><td class="label" colspan="2">${(0, lib_1.escapeHtml)(label)}</td><td class="number">${value}</td></tr>`;
|
|
96
|
+
/** No discount, no row. */
|
|
97
|
+
const renderDiscountRow = (input) => Number(input.totals.discount_total.amount) === 0
|
|
98
|
+
? ""
|
|
99
|
+
: renderTotalRow("Rabatt", renderDiscountTotal(input));
|
|
100
|
+
/**
|
|
101
|
+
* One row per tax rate. With several rates each row also names its net
|
|
102
|
+
* amount, since an invoice states the amount taxed at every rate.
|
|
103
|
+
*/
|
|
96
104
|
const renderTaxRows = (input) => {
|
|
97
105
|
const { tax_breakdown: breakdown, tax_total: taxTotal } = input.totals;
|
|
106
|
+
const withNetAmount = breakdown.length > 1;
|
|
98
107
|
const rows = breakdown.length > 0
|
|
99
108
|
? breakdown.map((entry) => ({
|
|
100
|
-
label:
|
|
109
|
+
label: [
|
|
110
|
+
`${entry.name} ${formatTaxRate(entry.rate)}`,
|
|
111
|
+
withNetAmount && entry.taxable_amount
|
|
112
|
+
? `auf ${(0, format_1.formatMoney)({
|
|
113
|
+
amount: entry.taxable_amount.amount,
|
|
114
|
+
currencyCode: entry.taxable_amount.currency_code,
|
|
115
|
+
})}`
|
|
116
|
+
: null,
|
|
117
|
+
]
|
|
118
|
+
.filter((part) => Boolean(part))
|
|
119
|
+
.join(" "),
|
|
101
120
|
money: entry.tax_total,
|
|
102
121
|
}))
|
|
103
122
|
: [{ label: "Umsatzsteuer", money: taxTotal }];
|
|
@@ -141,7 +160,7 @@ const renderFinancialDocument = (input, layout, timeZone) => {
|
|
|
141
160
|
<tbody class="totals">
|
|
142
161
|
${renderTotalRow("Zwischensumme", (0, html_utils_1.renderMoney)(totals.subtotal))}
|
|
143
162
|
${renderTotalRow("Versand", (0, html_utils_1.renderMoney)(totals.shipping_total))}
|
|
144
|
-
${
|
|
163
|
+
${renderDiscountRow(input)}
|
|
145
164
|
${renderTaxRows(input)}
|
|
146
165
|
${renderTotalRow("Gesamt", (0, html_utils_1.renderMoney)(totals.total), "grand-total")}
|
|
147
166
|
</tbody>
|
|
@@ -40,13 +40,20 @@ export type DocumentTaxBreakdownEntry = {
|
|
|
40
40
|
code: string | null;
|
|
41
41
|
rate: number;
|
|
42
42
|
tax_total: DocumentMoney;
|
|
43
|
+
/**
|
|
44
|
+
* Net amount taxed at this rate (items and their share of shipping, after
|
|
45
|
+
* discounts). Missing in snapshots issued before it was recorded.
|
|
46
|
+
*/
|
|
47
|
+
taxable_amount?: DocumentMoney;
|
|
43
48
|
};
|
|
44
49
|
export type DocumentTemplateLine = {
|
|
45
50
|
id: string;
|
|
46
51
|
title: string;
|
|
47
52
|
sku: string | null;
|
|
48
53
|
quantity: number;
|
|
54
|
+
/** Net, before discounts (older invoice snapshots: Medusa's unit price). */
|
|
49
55
|
unit_price: DocumentMoney;
|
|
56
|
+
/** Net, before discounts; printed under "Summe". */
|
|
50
57
|
subtotal: DocumentMoney;
|
|
51
58
|
tax_total: DocumentMoney;
|
|
52
59
|
total: DocumentMoney;
|
|
@@ -74,6 +81,12 @@ export type DocumentTemplateInput = {
|
|
|
74
81
|
tax_compliance: DocumentTaxComplianceDTO | null;
|
|
75
82
|
};
|
|
76
83
|
lines: DocumentTemplateLine[];
|
|
84
|
+
/**
|
|
85
|
+
* Subtotal (items) and shipping are net amounts before discounts, the
|
|
86
|
+
* discount is net, so they add up with the tax to the total. Older invoice
|
|
87
|
+
* snapshots carry Medusa's order subtotal (items plus shipping) and gross
|
|
88
|
+
* shipping and discount totals.
|
|
89
|
+
*/
|
|
77
90
|
totals: {
|
|
78
91
|
subtotal: DocumentMoney;
|
|
79
92
|
tax_total: DocumentMoney;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "@medusajs/framework/zod";
|
|
2
|
-
export declare const EMAIL_KINDS: readonly ["order.received", "order.received.admin", "order.shipped", "order.canceled", "order.return_requested", "order.return_received", "order.refunded", "auth.password_reset", "affiliate.consignment_report_due", "affiliate.application_submitted.admin", "user.invite", "auth.verification", "auth.login_code", "system.credential_expiry.admin"];
|
|
2
|
+
export declare const EMAIL_KINDS: readonly ["order.received", "order.received.admin", "order.shipped", "order.canceled", "order.return_requested", "order.return_received", "order.refunded", "auth.password_reset", "affiliate.consignment_report_due", "affiliate.application_submitted.admin", "user.invite", "auth.verification", "auth.login_code", "system.credential_expiry.admin", "auth.admin_password_reset"];
|
|
3
3
|
export declare const EmailKindSchema: z.ZodEnum<{
|
|
4
4
|
"order.received": "order.received";
|
|
5
5
|
"order.received.admin": "order.received.admin";
|
|
@@ -15,6 +15,7 @@ export declare const EmailKindSchema: z.ZodEnum<{
|
|
|
15
15
|
"auth.verification": "auth.verification";
|
|
16
16
|
"auth.login_code": "auth.login_code";
|
|
17
17
|
"system.credential_expiry.admin": "system.credential_expiry.admin";
|
|
18
|
+
"auth.admin_password_reset": "auth.admin_password_reset";
|
|
18
19
|
}>;
|
|
19
20
|
export type EmailKind = (typeof EMAIL_KINDS)[number];
|
|
20
21
|
/**
|
|
@@ -22,5 +23,5 @@ export type EmailKind = (typeof EMAIL_KINDS)[number];
|
|
|
22
23
|
* subscriber builds the mail from the event, so neither the generic retry
|
|
23
24
|
* job, the automatic dispatch nor an Admin resend may touch them.
|
|
24
25
|
*/
|
|
25
|
-
export declare const EPHEMERAL_EMAIL_KINDS: readonly ["auth.password_reset", "auth.verification", "auth.login_code"];
|
|
26
|
+
export declare const EPHEMERAL_EMAIL_KINDS: readonly ["auth.password_reset", "auth.admin_password_reset", "auth.verification", "auth.login_code"];
|
|
26
27
|
export declare const isEphemeralEmailKind: (kind: EmailKind) => boolean;
|
|
@@ -17,6 +17,7 @@ exports.EMAIL_KINDS = [
|
|
|
17
17
|
"auth.verification",
|
|
18
18
|
"auth.login_code",
|
|
19
19
|
"system.credential_expiry.admin",
|
|
20
|
+
"auth.admin_password_reset",
|
|
20
21
|
];
|
|
21
22
|
exports.EmailKindSchema = zod_1.z.enum(exports.EMAIL_KINDS);
|
|
22
23
|
/**
|
|
@@ -26,6 +27,7 @@ exports.EmailKindSchema = zod_1.z.enum(exports.EMAIL_KINDS);
|
|
|
26
27
|
*/
|
|
27
28
|
exports.EPHEMERAL_EMAIL_KINDS = [
|
|
28
29
|
"auth.password_reset",
|
|
30
|
+
"auth.admin_password_reset",
|
|
29
31
|
"auth.verification",
|
|
30
32
|
"auth.login_code",
|
|
31
33
|
];
|
|
@@ -48,6 +48,14 @@ export type ShopEmailConfiguration = Readonly<{
|
|
|
48
48
|
adminAffiliateApplicationsUrl?: (input: Readonly<{
|
|
49
49
|
applicationId: string;
|
|
50
50
|
}>) => string;
|
|
51
|
+
/**
|
|
52
|
+
* The Medusa Admin's "choose a new password" page with the reset token
|
|
53
|
+
* (`/app/reset-password?token=<token>`). Without it an Admin user's
|
|
54
|
+
* password reset sends no mail.
|
|
55
|
+
*/
|
|
56
|
+
adminPasswordResetUrl?: (input: Readonly<{
|
|
57
|
+
token: string;
|
|
58
|
+
}>) => string;
|
|
51
59
|
affiliatePortalUrl: string;
|
|
52
60
|
displayName: string;
|
|
53
61
|
inviteUrl: (input: Readonly<{
|
|
@@ -381,6 +381,7 @@ export declare const EmailPersistedDataSchemas: {
|
|
|
381
381
|
client_id: z.ZodString;
|
|
382
382
|
expires_on: z.ZodString;
|
|
383
383
|
}, z.core.$strict>;
|
|
384
|
+
readonly "auth.admin_password_reset": z.ZodObject<{}, z.core.$strict>;
|
|
384
385
|
};
|
|
385
386
|
export declare const EmailRenderDataSchemas: {
|
|
386
387
|
readonly "auth.password_reset": z.ZodObject<{
|
|
@@ -388,6 +389,10 @@ export declare const EmailRenderDataSchemas: {
|
|
|
388
389
|
reset_url: z.ZodString;
|
|
389
390
|
valid_minutes: z.ZodOptional<z.ZodNumber>;
|
|
390
391
|
}, z.core.$strict>;
|
|
392
|
+
readonly "auth.admin_password_reset": z.ZodObject<{
|
|
393
|
+
reset_url: z.ZodString;
|
|
394
|
+
valid_minutes: z.ZodOptional<z.ZodNumber>;
|
|
395
|
+
}, z.core.$strict>;
|
|
391
396
|
readonly "user.invite": z.ZodObject<{
|
|
392
397
|
invite_url: z.ZodString;
|
|
393
398
|
expires_at: z.ZodOptional<z.ZodString>;
|
|
@@ -635,7 +640,7 @@ export type EmailPersistedDataMap = {
|
|
|
635
640
|
};
|
|
636
641
|
type EmptyRenderContext = Readonly<Record<never, never>>;
|
|
637
642
|
export type EmailEphemeralRenderContextMap = {
|
|
638
|
-
readonly [Kind in EmailKind]: Kind extends "auth.password_reset" ? Readonly<{
|
|
643
|
+
readonly [Kind in EmailKind]: Kind extends "auth.password_reset" | "auth.admin_password_reset" ? Readonly<{
|
|
639
644
|
reset_url: string;
|
|
640
645
|
valid_minutes?: number;
|
|
641
646
|
}> : Kind extends "user.invite" ? Readonly<{
|
|
@@ -240,6 +240,8 @@ exports.EmailPersistedDataSchemas = {
|
|
|
240
240
|
expires_on: affiliate_1.CalendarDateSchema,
|
|
241
241
|
})
|
|
242
242
|
.strict(),
|
|
243
|
+
// The Admin dashboard is German only, so no locale; the link is ephemeral.
|
|
244
|
+
"auth.admin_password_reset": zod_1.z.object({}).strict(),
|
|
243
245
|
};
|
|
244
246
|
exports.EmailRenderDataSchemas = {
|
|
245
247
|
...exports.EmailPersistedDataSchemas,
|
|
@@ -248,6 +250,11 @@ exports.EmailRenderDataSchemas = {
|
|
|
248
250
|
/** How long the reset link is valid, from the token; `undefined` if unknown. */
|
|
249
251
|
valid_minutes: zod_1.z.number().int().positive().optional(),
|
|
250
252
|
}),
|
|
253
|
+
"auth.admin_password_reset": exports.EmailPersistedDataSchemas["auth.admin_password_reset"].extend({
|
|
254
|
+
reset_url: zod_1.z.string().url(),
|
|
255
|
+
/** How long the reset link is valid, from the token; `undefined` if unknown. */
|
|
256
|
+
valid_minutes: zod_1.z.number().int().positive().optional(),
|
|
257
|
+
}),
|
|
251
258
|
"user.invite": exports.EmailPersistedDataSchemas["user.invite"].extend({
|
|
252
259
|
invite_url: zod_1.z.string().url(),
|
|
253
260
|
/** When the invite expires (ISO 8601), from the current invite. */
|
package/dist/shared/lib/index.js
CHANGED
|
@@ -24,6 +24,7 @@ __exportStar(require("./hash"), exports);
|
|
|
24
24
|
__exportStar(require("./logging"), exports);
|
|
25
25
|
__exportStar(require("./money"), exports);
|
|
26
26
|
__exportStar(require("./refreshing-snapshot"), exports);
|
|
27
|
+
__exportStar(require("./shipping-tax"), exports);
|
|
27
28
|
__exportStar(require("./text"), exports);
|
|
28
29
|
__exportStar(require("./transaction"), exports);
|
|
29
30
|
__exportStar(require("./wire-response"), exports);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code of a shipping tax line whose rate is the item rates weighted by the
|
|
3
|
+
* items' net amount after discounts (shipping follows the main supplies,
|
|
4
|
+
* split by their Entgelt). Tax Compliance writes it; Documents splits such a
|
|
5
|
+
* line back onto the item tax rates by the same key, because an invoice
|
|
6
|
+
* states the tax per actual rate.
|
|
7
|
+
*/
|
|
8
|
+
export declare const APPORTIONED_SHIPPING_TAX_CODE = "shipping_blended";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.APPORTIONED_SHIPPING_TAX_CODE = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Code of a shipping tax line whose rate is the item rates weighted by the
|
|
6
|
+
* items' net amount after discounts (shipping follows the main supplies,
|
|
7
|
+
* split by their Entgelt). Tax Compliance writes it; Documents splits such a
|
|
8
|
+
* line back onto the item tax rates by the same key, because an invoice
|
|
9
|
+
* states the tax per actual rate.
|
|
10
|
+
*/
|
|
11
|
+
exports.APPORTIONED_SHIPPING_TAX_CODE = "shipping_blended";
|
|
@@ -172,6 +172,12 @@ function buildFoodShopConfig(options, environment = process.env) {
|
|
|
172
172
|
adminAffiliateApplicationsUrl: () => new URL("/app/affiliates/applications", backendOrigin).toString(),
|
|
173
173
|
// The Admin dashboard mounts under admin.path ("/app").
|
|
174
174
|
adminOrderUrl: ({ orderId }) => new URL(`/app/orders/${encodeURIComponent(orderId)}`, backendOrigin).toString(),
|
|
175
|
+
// The Admin dashboard reads the token from the query, not the hash.
|
|
176
|
+
adminPasswordResetUrl: ({ token }) => {
|
|
177
|
+
const url = new URL("/app/reset-password", backendOrigin);
|
|
178
|
+
url.searchParams.set("token", token);
|
|
179
|
+
return url.toString();
|
|
180
|
+
},
|
|
175
181
|
displayName: options.displayName,
|
|
176
182
|
affiliatePortalUrl: (0, config_1.shopUrl)(storefrontOrigin, `${storefrontPath}/partnerportal`),
|
|
177
183
|
// The Admin dashboard mounts "/invite" under admin.path ("/app").
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hartl-services/medusa-base",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "Base plugin for Hartl Services Medusa shops: per-plugin feature toggles with a generic Admin settings page, a Store endpoint for storefronts, enforcement helpers, the complete-cart hook composition, the root redirect, cart-promotion link repair, the built-in E-Mail, Documents and S3 file storage modules, config helpers with the turnkey food-shop preset, and the Sentry logger wrapper and instrumentation.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"mime-types": "3.0.1",
|
|
102
102
|
"nodemailer": "6.10.1",
|
|
103
103
|
"ulid": "^2.4.0",
|
|
104
|
-
"@hartl-services/medusa-food-supplements-contracts": "^0.
|
|
104
|
+
"@hartl-services/medusa-food-supplements-contracts": "^0.31.0"
|
|
105
105
|
},
|
|
106
106
|
"devDependencies": {
|
|
107
107
|
"@medusajs/admin-sdk": "2.19.0",
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
"dev": "medusa plugin:develop",
|
|
154
154
|
"typecheck": "tsc --noEmit && tsc -p tsconfig.type-tests.json --noEmit && tsc -p tsconfig.component-tests.json",
|
|
155
155
|
"pretest:unit": "pnpm --filter @hartl-services/medusa-food-supplements-contracts build",
|
|
156
|
-
"test:unit": "jest",
|
|
156
|
+
"test:unit": "sh ../../scripts/dev-capped.sh jest",
|
|
157
157
|
"pretest:contract": "pnpm --filter @hartl-services/medusa-food-supplements-contracts build",
|
|
158
158
|
"test:contract": "jest --config jest.contract.config.js --runInBand",
|
|
159
159
|
"test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --config jest.integration.config.js --silent=false --runInBand --forceExit"
|