@legenki/print2medusa 0.8.2 → 0.9.3
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 +200 -5
- package/.medusa/server/src/admin/index.mjs +201 -6
- package/.medusa/server/src/api/admin/printful/bundles/route.js +79 -0
- package/.medusa/server/src/api/admin/printful/design/route.js +38 -0
- package/.medusa/server/src/api/admin/printful/prompts/route.js +55 -0
- package/.medusa/server/src/utils/bundle.js +243 -0
- package/.medusa/server/src/utils/currency.js +68 -13
- package/.medusa/server/src/utils/design.js +438 -0
- package/.medusa/server/src/utils/printful-client.js +23 -1
- package/.medusa/server/src/utils/prompt.js +423 -0
- package/.medusa/server/src/workflows/apply-order-status.js +16 -5
- package/.medusa/server/src/workflows/create-printful-order.js +20 -3
- package/.medusa/server/src/workflows/sync-products.js +68 -1
- package/README.md +91 -0
- package/package.json +1 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GET = GET;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const design_1 = require("../../../../utils/design");
|
|
6
|
+
const prompt_1 = require("../../../../utils/prompt");
|
|
7
|
+
/**
|
|
8
|
+
* Mockup prompts per product.
|
|
9
|
+
*
|
|
10
|
+
* A pure read of the database plus string assembly — no Printful call, and no
|
|
11
|
+
* image generation. The plugin writes prompts; generation happens wherever you
|
|
12
|
+
* paste them, which is what keeps API keys, rate-limit queues and file storage
|
|
13
|
+
* out of this repo.
|
|
14
|
+
*/
|
|
15
|
+
async function GET(req, res) {
|
|
16
|
+
const productModule = req.scope.resolve(utils_1.Modules.PRODUCT);
|
|
17
|
+
const query = req.query;
|
|
18
|
+
// An unrecognized style falls back to the first preset rather than
|
|
19
|
+
// erroring: a mistyped query parameter should still produce prompts.
|
|
20
|
+
const requested = typeof query.style === "string" ? query.style : undefined;
|
|
21
|
+
const style = prompt_1.PROMPT_STYLES.some((s) => s.id === requested)
|
|
22
|
+
? requested
|
|
23
|
+
: undefined;
|
|
24
|
+
const artwork = typeof query.artwork === "string" && query.artwork.trim()
|
|
25
|
+
? query.artwork.trim()
|
|
26
|
+
: undefined;
|
|
27
|
+
const products = await productModule.listProducts({}, { relations: ["variants"], take: 100 });
|
|
28
|
+
const items = products
|
|
29
|
+
.map((product) => {
|
|
30
|
+
const summary = (0, design_1.summarizeProductDesign)(product.variants ?? []);
|
|
31
|
+
if (!summary) {
|
|
32
|
+
// Never enriched by a sync. Omitted rather than listed with no
|
|
33
|
+
// prompts, which would read as "this product cannot be prompted for".
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const prompts = (0, prompt_1.buildProductPrompts)({ design: summary, style, artwork });
|
|
37
|
+
if (prompts.length === 0) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
product_id: product.id,
|
|
42
|
+
title: product.title,
|
|
43
|
+
product_class: summary.product_class,
|
|
44
|
+
prompts,
|
|
45
|
+
};
|
|
46
|
+
})
|
|
47
|
+
.filter((p) => p !== null);
|
|
48
|
+
res.status(200).json({
|
|
49
|
+
products: items,
|
|
50
|
+
styles: prompt_1.PROMPT_STYLES.map((s) => ({ id: s.id, label: s.label })),
|
|
51
|
+
style: style ?? prompt_1.PROMPT_STYLES[0].id,
|
|
52
|
+
artwork,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3ByaW50ZnVsL3Byb21wdHMvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFpQkEsa0JBa0RDO0FBbEVELHFEQUFtRDtBQUNuRCxxREFBaUU7QUFDakUscURBSWlDO0FBRWpDOzs7Ozs7O0dBT0c7QUFDSSxLQUFLLFVBQVUsR0FBRyxDQUFDLEdBQWtCLEVBQUUsR0FBbUI7SUFDL0QsTUFBTSxhQUFhLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsZUFBTyxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ3hELE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxLQUFnQyxDQUFBO0lBRWxELG1FQUFtRTtJQUNuRSxxRUFBcUU7SUFDckUsTUFBTSxTQUFTLEdBQUcsT0FBTyxLQUFLLENBQUMsS0FBSyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFBO0lBQzNFLE1BQU0sS0FBSyxHQUFHLHNCQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLFNBQVMsQ0FBQztRQUN6RCxDQUFDLENBQUUsU0FBeUI7UUFDNUIsQ0FBQyxDQUFDLFNBQVMsQ0FBQTtJQUViLE1BQU0sT0FBTyxHQUNYLE9BQU8sS0FBSyxDQUFDLE9BQU8sS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUU7UUFDdkQsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFO1FBQ3RCLENBQUMsQ0FBQyxTQUFTLENBQUE7SUFFZixNQUFNLFFBQVEsR0FBRyxNQUFNLGFBQWEsQ0FBQyxZQUFZLENBQy9DLEVBQUUsRUFDRixFQUFFLFNBQVMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FDdkMsQ0FBQTtJQUVELE1BQU0sS0FBSyxHQUFHLFFBQVE7U0FDbkIsR0FBRyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7UUFDZixNQUFNLE9BQU8sR0FBRyxJQUFBLCtCQUFzQixFQUFDLE9BQU8sQ0FBQyxRQUFRLElBQUksRUFBRSxDQUFDLENBQUE7UUFDOUQsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2IsK0RBQStEO1lBQy9ELHNFQUFzRTtZQUN0RSxPQUFPLElBQUksQ0FBQTtRQUNiLENBQUM7UUFFRCxNQUFNLE9BQU8sR0FBRyxJQUFBLDRCQUFtQixFQUFDLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQTtRQUN4RSxJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDekIsT0FBTyxJQUFJLENBQUE7UUFDYixDQUFDO1FBRUQsT0FBTztZQUNMLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFBRTtZQUN0QixLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7WUFDcEIsYUFBYSxFQUFFLE9BQU8sQ0FBQyxhQUFhO1lBQ3BDLE9BQU87U0FDUixDQUFBO0lBQ0gsQ0FBQyxDQUFDO1NBQ0QsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUE4QixFQUFFLENBQUMsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUFBO0lBRXhELEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ25CLFFBQVEsRUFBRSxLQUFLO1FBQ2YsTUFBTSxFQUFFLHNCQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ2hFLEtBQUssRUFBRSxLQUFLLElBQUksc0JBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFO1FBQ25DLE9BQU87S0FDUixDQUFDLENBQUE7QUFDSixDQUFDIn0=
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Merch bundles: one Medusa product that stands for several Printful ones.
|
|
4
|
+
*
|
|
5
|
+
* Printful has no notion of a bundle — it fulfils individual items. So a
|
|
6
|
+
* bundle is a Medusa product whose variant records which member variants it
|
|
7
|
+
* contains, and order creation expands it back into those members.
|
|
8
|
+
*
|
|
9
|
+
* **Why expansion is mandatory rather than a nicety.** `create-printful-order`
|
|
10
|
+
* resolves one order line to one Printful item via `item.variant_id`. A bundle
|
|
11
|
+
* left unexpanded therefore ships a single thing where the customer bought
|
|
12
|
+
* three — or, if the bundle variant has no Printful link at all, the order is
|
|
13
|
+
* skipped as `no_printful_items` and nothing ships.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.BUNDLE_MEMBERS_KEY = void 0;
|
|
17
|
+
exports.bundleMembersOf = bundleMembersOf;
|
|
18
|
+
exports.isBundleLine = isBundleLine;
|
|
19
|
+
exports.expandOrderLines = expandOrderLines;
|
|
20
|
+
exports.medusaLineIdFor = medusaLineIdFor;
|
|
21
|
+
exports.planBundlePass = planBundlePass;
|
|
22
|
+
exports.planBundlePublication = planBundlePublication;
|
|
23
|
+
exports.planBundleAvailability = planBundleAvailability;
|
|
24
|
+
const stock_1 = require("./stock");
|
|
25
|
+
/** Statuses meaning a variant cannot be ordered. Mirrors `stock.ts`. */
|
|
26
|
+
const UNAVAILABLE = new Set([
|
|
27
|
+
"out_of_stock",
|
|
28
|
+
"temporary_out_of_stock",
|
|
29
|
+
"discontinued",
|
|
30
|
+
]);
|
|
31
|
+
/** Where a bundle's composition lives, on the variant and on the order line. */
|
|
32
|
+
exports.BUNDLE_MEMBERS_KEY = "printful_bundle_members";
|
|
33
|
+
/**
|
|
34
|
+
* The members recorded on a line, or nothing.
|
|
35
|
+
*
|
|
36
|
+
* Metadata is free-form JSON, so this validates rather than trusts: something
|
|
37
|
+
* else writing a string to this key must not crash order creation.
|
|
38
|
+
*/
|
|
39
|
+
function bundleMembersOf(line) {
|
|
40
|
+
const raw = (line?.metadata ?? {})[exports.BUNDLE_MEMBERS_KEY];
|
|
41
|
+
if (!Array.isArray(raw)) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const members = [];
|
|
45
|
+
for (const entry of raw) {
|
|
46
|
+
if (!entry || typeof entry !== "object") {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const variantId = entry.variant_id;
|
|
50
|
+
if (typeof variantId !== "string" || !variantId.trim()) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const quantity = Number(entry.quantity ?? 1);
|
|
54
|
+
members.push({
|
|
55
|
+
variant_id: variantId,
|
|
56
|
+
quantity: Number.isFinite(quantity) && quantity > 0 ? quantity : 1,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return members;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Whether a line stands for several products.
|
|
63
|
+
*
|
|
64
|
+
* A line whose member list is empty is *not* a bundle. Treating it as one
|
|
65
|
+
* would expand it to nothing, and an order of nothing looks identical to an
|
|
66
|
+
* order Printful was never asked about. Left alone, it flows through the
|
|
67
|
+
* ordinary unresolved-variant path, which reports it.
|
|
68
|
+
*/
|
|
69
|
+
function isBundleLine(line) {
|
|
70
|
+
return bundleMembersOf(line).length > 0;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Replace every bundle line with the lines it stands for.
|
|
74
|
+
*
|
|
75
|
+
* Composition is read from the line's own metadata, captured when the customer
|
|
76
|
+
* bought — never looked up live. A merchant who edits a bundle after a sale
|
|
77
|
+
* must not change what an already-placed order ships.
|
|
78
|
+
*
|
|
79
|
+
* Ordinary lines pass through untouched and keep their position, so a cart
|
|
80
|
+
* mixing bundles and singles reaches Printful in the order it was built.
|
|
81
|
+
*/
|
|
82
|
+
function expandOrderLines(lines) {
|
|
83
|
+
const out = [];
|
|
84
|
+
for (const line of lines) {
|
|
85
|
+
const members = bundleMembersOf(line);
|
|
86
|
+
if (members.length === 0) {
|
|
87
|
+
out.push(line);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
for (const member of members) {
|
|
91
|
+
out.push({
|
|
92
|
+
// Synthesised, but stable and traceable: two bundles in one cart
|
|
93
|
+
// cannot collide, and the id says where the line came from.
|
|
94
|
+
id: `${line.id}::${member.variant_id}`,
|
|
95
|
+
variant_id: member.variant_id,
|
|
96
|
+
title: line.title,
|
|
97
|
+
// Two bundles each holding two stickers is four stickers. Dropping
|
|
98
|
+
// this multiplication ships a customer half their order.
|
|
99
|
+
quantity: (member.quantity ?? 1) * Number(line.quantity || 1),
|
|
100
|
+
metadata: {},
|
|
101
|
+
bundle_line_id: line.id,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
/** Separates the bundle line id from the member variant id in a synthetic id. */
|
|
108
|
+
const SYNTHETIC_SEPARATOR = "::";
|
|
109
|
+
/**
|
|
110
|
+
* The Medusa line an `external_id` from Printful refers to.
|
|
111
|
+
*
|
|
112
|
+
* Expansion sends synthetic ids like `ordli_abc::variant_tee` as `external_id`,
|
|
113
|
+
* because Printful needs each item distinguishable and two members of one
|
|
114
|
+
* bundle would otherwise share the bundle line's id.
|
|
115
|
+
*
|
|
116
|
+
* Fulfillment reads those ids back to decide which Medusa line a parcel filled.
|
|
117
|
+
* Without this, a bundle's items resolve to an id no Medusa line has, every
|
|
118
|
+
* parcel clamps to zero open quantity, and the order is never marked shipped.
|
|
119
|
+
*
|
|
120
|
+
* A member id maps back to the *bundle* line, since that is the line the
|
|
121
|
+
* customer bought and the only one Medusa can fulfil.
|
|
122
|
+
*/
|
|
123
|
+
function medusaLineIdFor(externalId) {
|
|
124
|
+
const at = externalId.indexOf(SYNTHETIC_SEPARATOR);
|
|
125
|
+
return at === -1 ? externalId : externalId.slice(0, at);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Which bundle products the sync should rewrite, and to what.
|
|
129
|
+
*
|
|
130
|
+
* Bundles are invisible to the ordinary sync: they have no Printful product of
|
|
131
|
+
* their own, so no `sync_product` ever names them and the per-product loop
|
|
132
|
+
* never reaches them. Without this pass a bundle stays on sale after a member
|
|
133
|
+
* sells out, and every such order fails at Printful.
|
|
134
|
+
*
|
|
135
|
+
* Availability is read from the member variants passed in, not from the bundle
|
|
136
|
+
* — the bundle variant has no Printful status of its own to read.
|
|
137
|
+
*
|
|
138
|
+
* Returns only products that need writing, so a sync over a catalogue with no
|
|
139
|
+
* bundle changes issues no updates at all.
|
|
140
|
+
*/
|
|
141
|
+
function planBundlePass(input) {
|
|
142
|
+
const writes = [];
|
|
143
|
+
for (const bundle of input.bundles) {
|
|
144
|
+
const memberIds = (bundle.variants ?? []).flatMap((v) => bundleMembersOf({ id: v.id, quantity: 1, metadata: v.metadata }).map((m) => m.variant_id));
|
|
145
|
+
if (memberIds.length === 0) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
// A member variant the sync could not load is left out of the decision
|
|
149
|
+
// rather than counted as sold out: a failed lookup is not evidence that
|
|
150
|
+
// Printful ran out of anything, and drafting on it would hide a live
|
|
151
|
+
// bundle on a transient error.
|
|
152
|
+
const known = memberIds
|
|
153
|
+
.map((id) => input.variantsById.get(id))
|
|
154
|
+
.filter((v) => !!v);
|
|
155
|
+
// Knowing nothing about any member is not the same as knowing they are all
|
|
156
|
+
// in stock. Left to fall through, a bundle drafted for a sellout would be
|
|
157
|
+
// republished on the strength of a lookup that simply failed.
|
|
158
|
+
if (known.length === 0) {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const plan = planBundlePublication({
|
|
162
|
+
members: known,
|
|
163
|
+
currentStatus: bundle.status === "published" ? "published" : "draft",
|
|
164
|
+
currentMetadata: (bundle.metadata ?? {}),
|
|
165
|
+
});
|
|
166
|
+
if (!plan.changed) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
writes.push({
|
|
170
|
+
product_id: bundle.id,
|
|
171
|
+
status: plan.status,
|
|
172
|
+
metadata: plan.metadata,
|
|
173
|
+
missing: memberIds.filter((id) => {
|
|
174
|
+
const status = input.variantsById.get(id)?.metadata?.printful_availability_status;
|
|
175
|
+
return typeof status === "string" && UNAVAILABLE.has(status);
|
|
176
|
+
}),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return writes;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Whether a bundle should be published, from the stock of its members.
|
|
183
|
+
*
|
|
184
|
+
* Reuses `resolvePublication` so a bundle obeys the same ownership rule as
|
|
185
|
+
* every other product: the plugin undoes only unpublishes it performed, and a
|
|
186
|
+
* draft the merchant made themselves is left alone however available Printful
|
|
187
|
+
* says the members are.
|
|
188
|
+
*
|
|
189
|
+
* What differs is the threshold. `planStockActions` drafts a product only when
|
|
190
|
+
* *every* variant is gone, because any remaining variant is still sellable. A
|
|
191
|
+
* bundle is a promise to ship all of it, so one missing member already breaks
|
|
192
|
+
* the promise.
|
|
193
|
+
*
|
|
194
|
+
* A bundle with no members recorded is left untouched — that is a bundle the
|
|
195
|
+
* merchant has not finished configuring, not one that sold out.
|
|
196
|
+
*/
|
|
197
|
+
function planBundlePublication(input) {
|
|
198
|
+
const availability = planBundleAvailability(input.members.map((m) => m?.metadata ?? {}));
|
|
199
|
+
// One missing member is enough. A bundle with no members recorded has no
|
|
200
|
+
// unavailable ones either, so it falls through as available — an
|
|
201
|
+
// unconfigured bundle is not a sold-out one.
|
|
202
|
+
const allUnavailable = availability.unavailableCount > 0;
|
|
203
|
+
return (0, stock_1.resolvePublication)({
|
|
204
|
+
plan: {
|
|
205
|
+
allUnavailable,
|
|
206
|
+
status: allUnavailable ? "draft" : "published",
|
|
207
|
+
hasDiscontinued: false,
|
|
208
|
+
variantAvailability: {},
|
|
209
|
+
},
|
|
210
|
+
currentStatus: input.currentStatus,
|
|
211
|
+
currentMetadata: input.currentMetadata,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Whether a bundle can be sold, from the availability of its members.
|
|
216
|
+
*
|
|
217
|
+
* A bundle is a promise to ship all of it, so one sold-out member makes the
|
|
218
|
+
* promise unkeepable however available the rest are.
|
|
219
|
+
*
|
|
220
|
+
* Reads `printful_availability_status`, which the sync already writes — no new
|
|
221
|
+
* source of truth, and no second place to keep in step with Printful.
|
|
222
|
+
*
|
|
223
|
+
* An unknown status counts as available, matching `planStockActions`: the
|
|
224
|
+
* unavailable set is a closed list, and a bundle must not be stricter about a
|
|
225
|
+
* status than the member product itself is.
|
|
226
|
+
*/
|
|
227
|
+
function planBundleAvailability(members) {
|
|
228
|
+
let unavailable = 0;
|
|
229
|
+
for (const member of members) {
|
|
230
|
+
const status = member?.printful_availability_status;
|
|
231
|
+
if (typeof status === "string" && UNAVAILABLE.has(status)) {
|
|
232
|
+
unavailable += 1;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
// An empty bundle is unavailable rather than vacuously available: there is
|
|
237
|
+
// nothing to ship, which is not the same as everything being in stock.
|
|
238
|
+
available: members.length > 0 && unavailable === 0,
|
|
239
|
+
memberCount: members.length,
|
|
240
|
+
unavailableCount: unavailable,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVuZGxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL2J1bmRsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7OztHQVlHOzs7QUE4Q0gsMENBeUJDO0FBVUQsb0NBSUM7QUFZRCw0Q0E2QkM7QUFtQkQsMENBR0M7QUFtQ0Qsd0NBdURDO0FBd0JELHNEQXdCQztBQWVELHdEQW1CQztBQTlURCxtQ0FBb0U7QUFFcEUsd0VBQXdFO0FBQ3hFLE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxDQUFDO0lBQzFCLGNBQWM7SUFDZCx3QkFBd0I7SUFDeEIsY0FBYztDQUNmLENBQUMsQ0FBQTtBQUVGLGdGQUFnRjtBQUNuRSxRQUFBLGtCQUFrQixHQUFHLHlCQUF5QixDQUFBO0FBNEIzRDs7Ozs7R0FLRztBQUNILFNBQWdCLGVBQWUsQ0FDN0IsSUFBNEM7SUFFNUMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxJQUFJLEVBQUUsUUFBUSxJQUFJLEVBQUUsQ0FBQyxDQUFDLDBCQUFrQixDQUFDLENBQUE7SUFDdEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN4QixPQUFPLEVBQUUsQ0FBQTtJQUNYLENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBbUIsRUFBRSxDQUFBO0lBQ2xDLEtBQUssTUFBTSxLQUFLLElBQUksR0FBRyxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLEtBQUssSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUN4QyxTQUFRO1FBQ1YsQ0FBQztRQUNELE1BQU0sU0FBUyxHQUFJLEtBQXNCLENBQUMsVUFBVSxDQUFBO1FBQ3BELElBQUksT0FBTyxTQUFTLEtBQUssUUFBUSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7WUFDdkQsU0FBUTtRQUNWLENBQUM7UUFDRCxNQUFNLFFBQVEsR0FBRyxNQUFN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
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.minorUnitFactor = minorUnitFactor;
|
|
4
|
-
exports.isZeroDecimalCurrency = isZeroDecimalCurrency;
|
|
5
|
-
const utils_1 = require("@medusajs/framework/utils");
|
|
6
2
|
/**
|
|
7
3
|
* How many minor units make one major unit of a currency.
|
|
8
4
|
*
|
|
@@ -11,13 +7,73 @@ const utils_1 = require("@medusajs/framework/utils");
|
|
|
11
7
|
* Scaling those by 100 anyway produces a value a hundredfold too large for
|
|
12
8
|
* anything reading it back with Medusa's own conventions.
|
|
13
9
|
*
|
|
14
|
-
*
|
|
15
|
-
* `
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
10
|
+
* **Why the list is written out here rather than imported.** It used to come
|
|
11
|
+
* from `defaultCurrencies` in `@medusajs/framework/utils`, which is correct for
|
|
12
|
+
* server code and fatal for the browser: this file is also imported by the
|
|
13
|
+
* admin order widget, and `@medusajs/framework/utils` reaches
|
|
14
|
+
* `@medusajs/utils/dist/auth/token.js` → `jsonwebtoken` → `jws`, which calls
|
|
15
|
+
* `util.inherits`. That does not exist in a browser, so the whole Medusa admin
|
|
16
|
+
* failed to load with `chr.inherits is not a function` — not a broken widget,
|
|
17
|
+
* a blank admin.
|
|
18
|
+
*
|
|
19
|
+
* The usual objection to a hand-kept list is that HUF, ISK and CLP get missed.
|
|
20
|
+
* That is answered by a test rather than by discipline: `currency.test.ts`
|
|
21
|
+
* compares this set against Medusa's own table and fails if they diverge, so
|
|
22
|
+
* the data stays Medusa's while the import stays server-side.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.ZERO_DECIMAL_CURRENCIES = void 0;
|
|
26
|
+
exports.minorUnitFactor = minorUnitFactor;
|
|
27
|
+
exports.isZeroDecimalCurrency = isZeroDecimalCurrency;
|
|
28
|
+
/**
|
|
29
|
+
* Currencies with no subunit, from Medusa's `defaultCurrencies`
|
|
30
|
+
* (`decimal_digits === 0`). Kept in sync by test, not by hand.
|
|
31
|
+
*
|
|
32
|
+
* Exported so `currency.test.ts` can compare the set itself against Medusa's
|
|
33
|
+
* table in both directions — a code invented here is invisible to any check
|
|
34
|
+
* that only walks Medusa's side.
|
|
20
35
|
*/
|
|
36
|
+
exports.ZERO_DECIMAL_CURRENCIES = new Set([
|
|
37
|
+
"AFN",
|
|
38
|
+
"ALL",
|
|
39
|
+
"AMD",
|
|
40
|
+
"BIF",
|
|
41
|
+
"CLP",
|
|
42
|
+
"COP",
|
|
43
|
+
"CRC",
|
|
44
|
+
"DJF",
|
|
45
|
+
"GNF",
|
|
46
|
+
"HUF",
|
|
47
|
+
"IDR",
|
|
48
|
+
"IQD",
|
|
49
|
+
"IRR",
|
|
50
|
+
"IRT",
|
|
51
|
+
"ISK",
|
|
52
|
+
"JPY",
|
|
53
|
+
"KMF",
|
|
54
|
+
"KRW",
|
|
55
|
+
"LBP",
|
|
56
|
+
"MGA",
|
|
57
|
+
"MMK",
|
|
58
|
+
"MNT",
|
|
59
|
+
"MUR",
|
|
60
|
+
"PKR",
|
|
61
|
+
"PYG",
|
|
62
|
+
"RSD",
|
|
63
|
+
"RWF",
|
|
64
|
+
"SOS",
|
|
65
|
+
"SYP",
|
|
66
|
+
"TZS",
|
|
67
|
+
"UGX",
|
|
68
|
+
"UZS",
|
|
69
|
+
"VND",
|
|
70
|
+
"XAF",
|
|
71
|
+
"XOF",
|
|
72
|
+
"XPF",
|
|
73
|
+
"YER",
|
|
74
|
+
"ZMK",
|
|
75
|
+
"ZWL",
|
|
76
|
+
]);
|
|
21
77
|
function minorUnitFactor(currencyCode) {
|
|
22
78
|
return isZeroDecimalCurrency(currencyCode) ? 1 : 100;
|
|
23
79
|
}
|
|
@@ -36,7 +92,6 @@ function isZeroDecimalCurrency(currencyCode) {
|
|
|
36
92
|
return false;
|
|
37
93
|
}
|
|
38
94
|
// Printful sends "USD", Medusa stores "usd", and both reach this.
|
|
39
|
-
|
|
40
|
-
return entry?.decimal_digits === 0;
|
|
95
|
+
return exports.ZERO_DECIMAL_CURRENCIES.has(currencyCode.toUpperCase());
|
|
41
96
|
}
|
|
42
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
97
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VycmVuY3kuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvdXRpbHMvY3VycmVuY3kudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7OztBQW9ESCwwQ0FJQztBQVlELHNEQVFDO0FBMUVEOzs7Ozs7O0dBT0c7QUFDVSxRQUFBLHVCQUF1QixHQUFHLElBQUksR0FBRyxDQUFDO0lBQzdDLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztJQUNMLEtBQUs7SUFDTCxLQUFLO0lBQ0wsS0FBSztDQUNOLENBQUMsQ0FBQTtBQUVGLFNBQWdCLGVBQWUsQ0FDN0IsWUFBdUM7SUFFdkMsT0FBTyxxQkFBcUIsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUE7QUFDdEQsQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILFNBQWdCLHFCQUFxQixDQUNuQyxZQUF1QztJQUV2QyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDbEIsT0FBTyxLQUFLLENBQUE7SUFDZCxDQUFDO0lBQ0Qsa0VBQWtFO0lBQ2xFLE9BQU8sK0JBQXVCLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFBO0FBQ2hFLENBQUMifQ==
|