medusa-plugin-printify 0.1.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/jest.config.js +20 -0
- package/.medusa/server/jest.setup.js +4 -0
- package/.medusa/server/src/admin/index.js +472 -0
- package/.medusa/server/src/admin/index.mjs +473 -0
- package/.medusa/server/src/api/admin/plugin/route.js +7 -0
- package/.medusa/server/src/api/admin/printify/orders/[id]/submit/route.js +19 -0
- package/.medusa/server/src/api/admin/printify/orders/route.js +18 -0
- package/.medusa/server/src/api/admin/printify/products/[id]/route.js +113 -0
- package/.medusa/server/src/api/admin/printify/products/route.js +35 -0
- package/.medusa/server/src/api/admin/printify/shops/route.js +18 -0
- package/.medusa/server/src/api/middlewares.js +12 -0
- package/.medusa/server/src/api/store/plugin/route.js +7 -0
- package/.medusa/server/src/api/webhooks/printify/route.js +102 -0
- package/.medusa/server/src/jobs/auto-submit-orders-job.js +31 -0
- package/.medusa/server/src/jobs/sync-products-job.js +23 -0
- package/.medusa/server/src/lib/webhook-utils.js +13 -0
- package/.medusa/server/src/links/printify-order-medusa-order.js +10 -0
- package/.medusa/server/src/links/printify-product-medusa-product.js +10 -0
- package/.medusa/server/src/modules/printify/api-client.js +67 -0
- package/.medusa/server/src/modules/printify/index.js +13 -0
- package/.medusa/server/src/modules/printify/migrations/Migration20260305115907.js +21 -0
- package/.medusa/server/src/modules/printify/migrations/Migration20260313185144.js +14 -0
- package/.medusa/server/src/modules/printify/models/order.js +18 -0
- package/.medusa/server/src/modules/printify/models/product.js +22 -0
- package/.medusa/server/src/modules/printify/models/shop.js +11 -0
- package/.medusa/server/src/modules/printify/service.js +38 -0
- package/.medusa/server/src/modules/printify/types.js +3 -0
- package/.medusa/server/src/subscribers/order-placed.js +55 -0
- package/.medusa/server/src/subscribers/plugin-registered.js +37 -0
- package/.medusa/server/src/utils/build-variant-prices.js +17 -0
- package/.medusa/server/src/utils/currency-converter.js +46 -0
- package/.medusa/server/src/workflows/create-printify-order.js +86 -0
- package/.medusa/server/src/workflows/index.js +12 -0
- package/.medusa/server/src/workflows/option-mapper.js +64 -0
- package/.medusa/server/src/workflows/submit-printify-order.js +29 -0
- package/.medusa/server/src/workflows/sync-products.js +313 -0
- package/.medusa/server/src/workflows/sync-shops.js +30 -0
- package/README.md +253 -0
- package/package.json +78 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildVariantPrices = buildVariantPrices;
|
|
4
|
+
const currency_converter_1 = require("./currency-converter");
|
|
5
|
+
/**
|
|
6
|
+
* Builds a Medusa-compatible prices array for a variant,
|
|
7
|
+
* converting the Printify USD price (in cents) to all active currencies.
|
|
8
|
+
* Medusa stores amounts in major currency units (e.g. 19.99 = $19.99).
|
|
9
|
+
*/
|
|
10
|
+
function buildVariantPrices(printifyPriceUsdCents, currencies, rates) {
|
|
11
|
+
const priceInDollars = (printifyPriceUsdCents ?? 0) / 100;
|
|
12
|
+
return currencies.map((currency) => ({
|
|
13
|
+
amount: (0, currency_converter_1.convertPrice)(priceInDollars, currency, rates),
|
|
14
|
+
currency_code: currency,
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGQtdmFyaWFudC1wcmljZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvdXRpbHMvYnVpbGQtdmFyaWFudC1wcmljZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFPQSxnREFVQztBQWpCRCw2REFBdUU7QUFFdkU7Ozs7R0FJRztBQUNILFNBQWdCLGtCQUFrQixDQUNoQyxxQkFBNkIsRUFDN0IsVUFBb0IsRUFDcEIsS0FBb0I7SUFFcEIsTUFBTSxjQUFjLEdBQUcsQ0FBQyxxQkFBcUIsSUFBSSxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUE7SUFDekQsT0FBTyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ25DLE1BQU0sRUFBRSxJQUFBLGlDQUFZLEVBQUMsY0FBYyxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUM7UUFDckQsYUFBYSxFQUFFLFFBQVE7S0FDeEIsQ0FBQyxDQUFDLENBQUE7QUFDTCxDQUFDIn0=
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.fetchExchangeRates = fetchExchangeRates;
|
|
7
|
+
exports.convertPrice = convertPrice;
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
/**
|
|
10
|
+
* Fetches latest exchange rates from USD to the given currency codes
|
|
11
|
+
* using the Frankfurter API (free, ECB-backed, no API key needed).
|
|
12
|
+
* Returns a map of lowercase currency_code → rate relative to USD.
|
|
13
|
+
*/
|
|
14
|
+
async function fetchExchangeRates(currencyCodes) {
|
|
15
|
+
const nonUsd = currencyCodes
|
|
16
|
+
.map((c) => c.toLowerCase())
|
|
17
|
+
.filter((c) => c !== "usd");
|
|
18
|
+
if (nonUsd.length === 0)
|
|
19
|
+
return {};
|
|
20
|
+
try {
|
|
21
|
+
const symbols = nonUsd.map((c) => c.toUpperCase()).join(",");
|
|
22
|
+
const { data } = await axios_1.default.get("https://api.frankfurter.dev/v1/latest", { params: { base: "USD", symbols }, timeout: 10000 });
|
|
23
|
+
const rates = {};
|
|
24
|
+
for (const [code, rate] of Object.entries(data.rates)) {
|
|
25
|
+
rates[code.toLowerCase()] = rate;
|
|
26
|
+
}
|
|
27
|
+
return rates;
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
throw new Error(`Failed to fetch exchange rates: ${err instanceof Error ? err.message : err}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Converts a price in USD to the target currency using the given rates.
|
|
35
|
+
* Returns the converted amount rounded to 2 decimal places.
|
|
36
|
+
*/
|
|
37
|
+
function convertPrice(amountInUsd, targetCurrency, rates) {
|
|
38
|
+
const currency = targetCurrency.toLowerCase();
|
|
39
|
+
if (currency === "usd")
|
|
40
|
+
return amountInUsd;
|
|
41
|
+
const rate = rates[currency];
|
|
42
|
+
if (rate == null)
|
|
43
|
+
throw new Error(`No exchange rate for ${currency}`);
|
|
44
|
+
return Math.round(amountInUsd * rate * 100) / 100;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VycmVuY3ktY29udmVydGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL2N1cnJlbmN5LWNvbnZlcnRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVNBLGdEQXlCQztBQU1ELG9DQVVDO0FBbERELGtEQUF5QjtBQUl6Qjs7OztHQUlHO0FBQ0ksS0FBSyxVQUFVLGtCQUFrQixDQUN0QyxhQUF1QjtJQUV2QixNQUFNLE1BQU0sR0FBRyxhQUFhO1NBQ3pCLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO1NBQzNCLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLEtBQUssQ0FBQyxDQUFBO0lBRTdCLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQUUsT0FBTyxFQUFFLENBQUE7SUFFbEMsSUFBSSxDQUFDO1FBQ0gsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1FBQzVELE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxNQUFNLGVBQUssQ0FBQyxHQUFHLENBQzlCLHVDQUF1QyxFQUN2QyxFQUFFLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxDQUNyRCxDQUFBO1FBQ0QsTUFBTSxLQUFLLEdBQWtCLEVBQUUsQ0FBQTtRQUMvQixLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN0RCxLQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLEdBQUcsSUFBYyxDQUFBO1FBQzVDLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQTtJQUNkLENBQUM7SUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ2IsTUFBTSxJQUFJLEtBQUssQ0FDYixtQ0FBbUMsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQzlFLENBQUE7SUFDSCxDQUFDO0FBQ0gsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLFlBQVksQ0FDMUIsV0FBbUIsRUFDbkIsY0FBc0IsRUFDdEIsS0FBb0I7SUFFcEIsTUFBTSxRQUFRLEdBQUcsY0FBYyxDQUFDLFdBQVcsRUFBRSxDQUFBO0lBQzdDLElBQUksUUFBUSxLQUFLLEtBQUs7UUFBRSxPQUFPLFdBQVcsQ0FBQTtJQUMxQyxNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUE7SUFDNUIsSUFBSSxJQUFJLElBQUksSUFBSTtRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsd0JBQXdCLFFBQVEsRUFBRSxDQUFDLENBQUE7SUFDckUsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsR0FBRyxJQUFJLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxDQUFBO0FBQ25ELENBQUMifQ==
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createPrintifyOrderWorkflow = void 0;
|
|
4
|
+
const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
|
|
5
|
+
const printify_1 = require("../modules/printify");
|
|
6
|
+
const buildOrderPayloadStep = (0, workflows_sdk_1.createStep)("printify-build-order-payload-step", async (input) => {
|
|
7
|
+
const address = {
|
|
8
|
+
first_name: input.address.firstName,
|
|
9
|
+
last_name: input.address.lastName,
|
|
10
|
+
email: input.address.email,
|
|
11
|
+
phone: input.address.phone,
|
|
12
|
+
address1: input.address.address1,
|
|
13
|
+
address2: input.address.address2,
|
|
14
|
+
city: input.address.city,
|
|
15
|
+
region: input.address.province,
|
|
16
|
+
zip: input.address.postalCode,
|
|
17
|
+
country: input.address.countryCode.toUpperCase(),
|
|
18
|
+
};
|
|
19
|
+
const payload = {
|
|
20
|
+
external_id: input.medusaOrderId,
|
|
21
|
+
label: `Medusa Order ${input.medusaOrderId}`,
|
|
22
|
+
line_items: input.lineItems.map((item) => ({
|
|
23
|
+
product_id: item.printify_product_id,
|
|
24
|
+
variant_id: item.variant_id,
|
|
25
|
+
quantity: item.quantity,
|
|
26
|
+
})),
|
|
27
|
+
shipping_method: input.shippingMethod,
|
|
28
|
+
send_shipping_notification: false,
|
|
29
|
+
address_to: address,
|
|
30
|
+
};
|
|
31
|
+
return new workflows_sdk_1.StepResponse({ payload, address });
|
|
32
|
+
});
|
|
33
|
+
const createOrderInPrintifyStep = (0, workflows_sdk_1.createStep)("printify-create-order-in-printify-step", async ({ payload, shopId }, { container }) => {
|
|
34
|
+
const service = container.resolve(printify_1.PRINTIFY_MODULE);
|
|
35
|
+
const order = await service.getApiClient().createOrder(shopId, payload);
|
|
36
|
+
return new workflows_sdk_1.StepResponse(order, order.id);
|
|
37
|
+
}, async (printifyOrderId) => {
|
|
38
|
+
console.warn(`[printify] compensation: order ${printifyOrderId} may need manual cancellation in Printify`);
|
|
39
|
+
});
|
|
40
|
+
const persistLocalOrderStep = (0, workflows_sdk_1.createStep)("printify-persist-local-order-step", async ({ printifyOrder, input, address }, { container }) => {
|
|
41
|
+
const service = container.resolve(printify_1.PRINTIFY_MODULE);
|
|
42
|
+
// Capture variant costs immutably at order creation time
|
|
43
|
+
const costPerItem = {};
|
|
44
|
+
let totalCost = 0;
|
|
45
|
+
for (const item of input.lineItems) {
|
|
46
|
+
const products = await service.listPrintifyProducts({
|
|
47
|
+
printify_id: String(item.printify_product_id),
|
|
48
|
+
});
|
|
49
|
+
if (products.length > 0) {
|
|
50
|
+
const product = products[0];
|
|
51
|
+
const variants = product.variants || [];
|
|
52
|
+
const variant = variants.find((v) => v.id === item.variant_id);
|
|
53
|
+
if (variant) {
|
|
54
|
+
costPerItem[`${item.printify_product_id}:${item.variant_id}`] = variant.cost;
|
|
55
|
+
totalCost += variant.cost * item.quantity;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const created = await service.createPrintifyOrders([
|
|
60
|
+
{
|
|
61
|
+
printify_id: String(printifyOrder.id),
|
|
62
|
+
shop_id: input.shopId,
|
|
63
|
+
medusa_order_id: input.medusaOrderId,
|
|
64
|
+
status: printifyOrder.status || "pending",
|
|
65
|
+
shipping_method: String(input.shippingMethod),
|
|
66
|
+
line_items: input.lineItems,
|
|
67
|
+
address_to: address,
|
|
68
|
+
total_cost: totalCost || null,
|
|
69
|
+
cost_per_item: Object.keys(costPerItem).length > 0 ? costPerItem : null,
|
|
70
|
+
submitted_at: null,
|
|
71
|
+
},
|
|
72
|
+
]);
|
|
73
|
+
const localOrder = Array.isArray(created) ? created[0] : created;
|
|
74
|
+
return new workflows_sdk_1.StepResponse({
|
|
75
|
+
printifyOrderId: printifyOrder.id,
|
|
76
|
+
localOrderId: localOrder.id,
|
|
77
|
+
status: printifyOrder.status,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
exports.createPrintifyOrderWorkflow = (0, workflows_sdk_1.createWorkflow)("create-printify-order", (input) => {
|
|
81
|
+
const { payload, address } = buildOrderPayloadStep(input);
|
|
82
|
+
const printifyOrder = createOrderInPrintifyStep({ payload, shopId: input.shopId });
|
|
83
|
+
const result = persistLocalOrderStep({ printifyOrder, input, address });
|
|
84
|
+
return new workflows_sdk_1.WorkflowResponse(result);
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLXByaW50aWZ5LW9yZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9jcmVhdGUtcHJpbnRpZnktb3JkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBSzBDO0FBQzFDLGtEQUFxRDtBQW9DckQsTUFBTSxxQkFBcUIsR0FBRyxJQUFBLDBCQUFVLEVBQ3RDLG1DQUFtQyxFQUNuQyxLQUFLLEVBQUUsS0FBK0IsRUFBNkMsRUFBRTtJQUNuRixNQUFNLE9BQU8sR0FBb0I7UUFDL0IsVUFBVSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsU0FBUztRQUNuQyxTQUFTLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRO1FBQ2pDLEtBQUssRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUs7UUFDMUIsS0FBSyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSztRQUMxQixRQUFRLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRO1FBQ2hDLFFBQVEsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVE7UUFDaEMsSUFBSSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSTtRQUN4QixNQUFNLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRO1FBQzlCLEdBQUcsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLFVBQVU7UUFDN0IsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLFdBQVcsRUFBRTtLQUNqRCxDQUFBO0lBRUQsTUFBTSxPQUFPLEdBQStCO1FBQzFDLFdBQVcsRUFBRSxLQUFLLENBQUMsYUFBYTtRQUNoQyxLQUFLLEVBQUUsZ0JBQWdCLEtBQUssQ0FBQyxhQUFhLEVBQUU7UUFDNUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3pDLFVBQVUs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
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.submitPrintifyOrderWorkflow = exports.createPrintifyOrderWorkflow = exports.syncProductsWorkflow = exports.syncShopsWorkflow = void 0;
|
|
4
|
+
var sync_shops_1 = require("./sync-shops");
|
|
5
|
+
Object.defineProperty(exports, "syncShopsWorkflow", { enumerable: true, get: function () { return sync_shops_1.syncShopsWorkflow; } });
|
|
6
|
+
var sync_products_1 = require("./sync-products");
|
|
7
|
+
Object.defineProperty(exports, "syncProductsWorkflow", { enumerable: true, get: function () { return sync_products_1.syncProductsWorkflow; } });
|
|
8
|
+
var create_printify_order_1 = require("./create-printify-order");
|
|
9
|
+
Object.defineProperty(exports, "createPrintifyOrderWorkflow", { enumerable: true, get: function () { return create_printify_order_1.createPrintifyOrderWorkflow; } });
|
|
10
|
+
var submit_printify_order_1 = require("./submit-printify-order");
|
|
11
|
+
Object.defineProperty(exports, "submitPrintifyOrderWorkflow", { enumerable: true, get: function () { return submit_printify_order_1.submitPrintifyOrderWorkflow; } });
|
|
12
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvd29ya2Zsb3dzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJDQUFnRDtBQUF2QywrR0FBQSxpQkFBaUIsT0FBQTtBQUMxQixpREFBc0Q7QUFBN0MscUhBQUEsb0JBQW9CLE9BQUE7QUFDN0IsaUVBQW9HO0FBQTNGLG9JQUFBLDJCQUEyQixPQUFBO0FBQ3BDLGlFQUFxRTtBQUE1RCxvSUFBQSwyQkFBMkIsT0FBQSJ9
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mapPrintifyOptions = mapPrintifyOptions;
|
|
4
|
+
function mapPrintifyOptions(options, variants, images) {
|
|
5
|
+
if (!options || options.length === 0) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
// Build lookup: option value ID -> { optionName, valueTitle }
|
|
9
|
+
const valueLookup = new Map();
|
|
10
|
+
for (const opt of options) {
|
|
11
|
+
for (const val of opt.values) {
|
|
12
|
+
valueLookup.set(val.id, { optionName: opt.name, valueTitle: val.title });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const enabledVariants = variants.filter((v) => v.is_enabled);
|
|
16
|
+
if (enabledVariants.length === 0) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
// Build variant option map: printify variant ID -> { OptionName: ValueTitle }
|
|
20
|
+
const variantOptionMap = new Map();
|
|
21
|
+
for (const v of enabledVariants) {
|
|
22
|
+
const optionValues = {};
|
|
23
|
+
for (const valId of v.options) {
|
|
24
|
+
const lookup = valueLookup.get(valId);
|
|
25
|
+
if (lookup) {
|
|
26
|
+
optionValues[lookup.optionName] = lookup.valueTitle;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
variantOptionMap.set(v.id, optionValues);
|
|
30
|
+
}
|
|
31
|
+
// Collect only option values used by enabled variants
|
|
32
|
+
const usedValueIds = new Set();
|
|
33
|
+
for (const v of enabledVariants) {
|
|
34
|
+
for (const valId of v.options) {
|
|
35
|
+
usedValueIds.add(valId);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Build Medusa options with only used values, preserving Printify option order
|
|
39
|
+
const medusaOptions = options
|
|
40
|
+
.map((opt) => ({
|
|
41
|
+
title: opt.name,
|
|
42
|
+
values: [...new Set(opt.values
|
|
43
|
+
.filter((val) => usedValueIds.has(val.id))
|
|
44
|
+
.map((val) => val.title))],
|
|
45
|
+
}))
|
|
46
|
+
.filter((opt) => opt.values.length > 0);
|
|
47
|
+
// Build variant image map: printify variant ID -> image URLs
|
|
48
|
+
const enabledIds = new Set(enabledVariants.map((v) => v.id));
|
|
49
|
+
const variantImageMap = new Map();
|
|
50
|
+
for (const img of images) {
|
|
51
|
+
if (!img.variant_ids)
|
|
52
|
+
continue;
|
|
53
|
+
for (const vid of img.variant_ids) {
|
|
54
|
+
if (!enabledIds.has(vid))
|
|
55
|
+
continue;
|
|
56
|
+
if (!variantImageMap.has(vid)) {
|
|
57
|
+
variantImageMap.set(vid, []);
|
|
58
|
+
}
|
|
59
|
+
variantImageMap.get(vid).push({ url: img.src });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { medusaOptions, variantOptionMap, variantImageMap };
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3B0aW9uLW1hcHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy93b3JrZmxvd3Mvb3B0aW9uLW1hcHBlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQVFBLGdEQXVFQztBQXZFRCxTQUFnQixrQkFBa0IsQ0FDaEMsT0FBeUIsRUFDekIsUUFBMkIsRUFDM0IsTUFBdUI7SUFFdkIsSUFBSSxDQUFDLE9BQU8sSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3JDLE9BQU8sSUFBSSxDQUFBO0lBQ2IsQ0FBQztJQUVELDhEQUE4RDtJQUM5RCxNQUFNLFdBQVcsR0FBRyxJQUFJLEdBQUcsRUFBc0QsQ0FBQTtJQUNqRixLQUFLLE1BQU0sR0FBRyxJQUFJLE9BQU8sRUFBRSxDQUFDO1FBQzFCLEtBQUssTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQzdCLFdBQVcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxHQUFHLENBQUMsSUFBSSxFQUFFLFVBQVUsRUFBRSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQTtRQUMxRSxDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sZUFBZSxHQUFHLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUU1RCxJQUFJLGVBQWUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDakMsT0FBTyxJQUFJLENBQUE7SUFDYixDQUFDO0lBRUQsOEVBQThFO0lBQzlFLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxHQUFHLEVBQWtDLENBQUE7SUFDbEUsS0FBSyxNQUFNLENBQUMsSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUNoQyxNQUFNLFlBQVksR0FBMkIsRUFBRSxDQUFBO1FBQy9DLEtBQUssTUFBTSxLQUFLLElBQUksQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQzlCLE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUE7WUFDckMsSUFBSSxNQUFNLEVBQUUsQ0FBQztnQkFDWCxZQUFZLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUE7WUFDckQsQ0FBQztRQUNILENBQUM7UUFDRCxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxZQUFZLENBQUMsQ0FBQTtJQUMxQyxDQUFDO0lBRUQsc0RBQXNEO0lBQ3RELE1BQU0sWUFBWSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUE7SUFDdEMsS0FBSyxNQUFNLENBQUMsSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUNoQyxLQUFLLE1BQU0sS0FBSyxJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUM5QixZQUFZLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBQ3pCLENBQUM7SUFDSCxDQUFDO0lBRUQsK0VBQStFO0lBQy9FLE1BQU0sYUFBYSxHQUFHLE9BQU87U0FDMUIsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ2IsS0FBSyxFQUFFLEdBQUcsQ0FBQyxJQUFJO1FBQ2YsTUFBTSxFQUFFLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FDakIsR0FBRyxDQUFDLE1BQU07aUJBQ1AsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztpQkFDekMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQzNCLENBQUM7S0FDSCxDQUFDLENBQUM7U0FDRixNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFBO0lBRXpDLDZEQUE2RDtJQUM3RCxNQUFNLFVBQVUsR0FBRyxJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQTtJQUM1RCxNQUFNLGVBQWUsR0FBRyxJQUFJLEdBQUcsRUFBNkIsQ0FBQTtJQUM1RCxLQUFLLE1BQU0sR0FBRyxJQUFJLE1BQU0sRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxHQUFHLENBQUMsV0FBVztZQUFFLFNBQVE7UUFDOUIsS0FBSyxNQUFNLEdBQUcsSUFBSSxHQUFHLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDbEMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDO2dCQUFFLFNBQVE7WUFDbEMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDOUIsZUFBZSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUE7WUFDOUIsQ0FBQztZQUNELGVBQWUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFBO1FBQ2xELENBQUM7SUFDSCxDQUFDO0lBRUQsT0FBTyxFQUFFLGFBQWEsRUFBRSxnQkFBZ0IsRUFBRSxlQUFlLEVBQUUsQ0FBQTtBQUM3RCxDQUFDIn0=
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.submitPrintifyOrderWorkflow = void 0;
|
|
4
|
+
const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
|
|
5
|
+
const printify_1 = require("../modules/printify");
|
|
6
|
+
const submitOrderStep = (0, workflows_sdk_1.createStep)("printify-submit-order-step", async ({ localOrderId, shopId }, { container }) => {
|
|
7
|
+
const service = container.resolve(printify_1.PRINTIFY_MODULE);
|
|
8
|
+
const orders = await service.listPrintifyOrders({ id: localOrderId });
|
|
9
|
+
const localOrder = orders[0];
|
|
10
|
+
if (!localOrder) {
|
|
11
|
+
throw new Error(`PrintifyOrder not found: ${localOrderId}`);
|
|
12
|
+
}
|
|
13
|
+
if (!localOrder.printify_id) {
|
|
14
|
+
throw new Error(`PrintifyOrder ${localOrderId} has no printify_id — cannot submit`);
|
|
15
|
+
}
|
|
16
|
+
const submitted = await service
|
|
17
|
+
.getApiClient()
|
|
18
|
+
.submitOrder(shopId, localOrder.printify_id);
|
|
19
|
+
await service.updatePrintifyOrders({ id: localOrderId }, { status: submitted.status, submitted_at: new Date() });
|
|
20
|
+
return new workflows_sdk_1.StepResponse({
|
|
21
|
+
status: submitted.status,
|
|
22
|
+
printifyOrderId: localOrder.printify_id,
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
exports.submitPrintifyOrderWorkflow = (0, workflows_sdk_1.createWorkflow)("submit-printify-order", (input) => {
|
|
26
|
+
const result = submitOrderStep(input);
|
|
27
|
+
return new workflows_sdk_1.WorkflowResponse(result);
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VibWl0LXByaW50aWZ5LW9yZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3dvcmtmbG93cy9zdWJtaXQtcHJpbnRpZnktb3JkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUVBSzBDO0FBQzFDLGtEQUFxRDtBQWFyRCxNQUFNLGVBQWUsR0FBRyxJQUFBLDBCQUFVLEVBQ2hDLDRCQUE0QixFQUM1QixLQUFLLEVBQUUsRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUE0QixFQUFFLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRTtJQUMxRSxNQUFNLE9BQU8sR0FBMEIsU0FBUyxDQUFDLE9BQU8sQ0FBQywwQkFBZSxDQUFDLENBQUE7SUFFekUsTUFBTSxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsa0JBQWtCLENBQUMsRUFBRSxFQUFFLEVBQUUsWUFBWSxFQUFFLENBQUMsQ0FBQTtJQUNyRSxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFFNUIsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2hCLE1BQU0sSUFBSSxLQUFLLENBQUMsNEJBQTRCLFlBQVksRUFBRSxDQUFDLENBQUE7SUFDN0QsQ0FBQztJQUNELElBQUksQ0FBQyxVQUFVLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsWUFBWSxxQ0FBcUMsQ0FBQyxDQUFBO0lBQ3JGLENBQUM7SUFFRCxNQUFNLFNBQVMsR0FBRyxNQUFNLE9BQU87U0FDNUIsWUFBWSxFQUFFO1NBQ2QsV0FBVyxDQUFDLE1BQU0sRUFBRSxVQUFVLENBQUMsV0FBcUIsQ0FBQyxDQUFBO0lBRXhELE1BQU0sT0FBTyxDQUFDLG9CQUFvQixDQUNoQyxFQUFFLEVBQUUsRUFBRSxZQUFZLEVBQUUsRUFDcEIsRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDLE1BQU0sRUFBRSxZQUFZLEVBQUUsSUFBSSxJQUFJLEVBQUUsRUFBRSxDQUN2RCxDQUFBO0lBRUQsT0FBTyxJQUFJLDRCQUFZLENBQUM7UUFDdEIsTUFBTSxFQUFFLFNBQVMsQ0FBQyxNQUFNO1FBQ3hCLGVBQWUsRUFBRSxVQUFVLENBQUMsV0FBcUI7S0FDbEQsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUNGLENBQUE7QUFFWSxRQUFBLDJCQUEyQixHQUFHLElBQUEsOEJBQWMsRUFDdkQsdUJBQXVCLEVBQ3ZCLENBQUMsS0FBK0IsRUFBRSxFQUFFO0lBQ2xDLE1BQU0sTUFBTSxHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUNyQyxPQUFPLElBQUksZ0NBQWdCLENBQUMsTUFBTSxDQUFDLENBQUE7QUFDckMsQ0FBQyxDQUNGLENBQUEifQ==
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.syncProductsWorkflow = void 0;
|
|
4
|
+
const workflows_sdk_1 = require("@medusajs/framework/workflows-sdk");
|
|
5
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
6
|
+
const core_flows_1 = require("@medusajs/medusa/core-flows");
|
|
7
|
+
const printify_1 = require("../modules/printify");
|
|
8
|
+
const option_mapper_1 = require("./option-mapper");
|
|
9
|
+
const currency_converter_1 = require("../utils/currency-converter");
|
|
10
|
+
const build_variant_prices_1 = require("../utils/build-variant-prices");
|
|
11
|
+
const fetchAllProductsStep = (0, workflows_sdk_1.createStep)("printify-fetch-all-products-step", async ({ shopId }, { container }) => {
|
|
12
|
+
const service = container.resolve(printify_1.PRINTIFY_MODULE);
|
|
13
|
+
const client = service.getApiClient();
|
|
14
|
+
const products = [];
|
|
15
|
+
let page = 1;
|
|
16
|
+
let lastPage = 1;
|
|
17
|
+
do {
|
|
18
|
+
const response = await client.getProducts(shopId, page, 50);
|
|
19
|
+
products.push(...response.data);
|
|
20
|
+
lastPage = response.last_page;
|
|
21
|
+
page++;
|
|
22
|
+
} while (page <= lastPage);
|
|
23
|
+
return new workflows_sdk_1.StepResponse(products);
|
|
24
|
+
});
|
|
25
|
+
const upsertProductsStep = (0, workflows_sdk_1.createStep)("printify-upsert-products-step", async ({ products, shopId }, { container }) => {
|
|
26
|
+
const service = container.resolve(printify_1.PRINTIFY_MODULE);
|
|
27
|
+
for (const product of products) {
|
|
28
|
+
const existing = await service.listPrintifyProducts({ printify_id: String(product.id) });
|
|
29
|
+
const printifyPublished = product.visible && !product.is_locked;
|
|
30
|
+
// visibility_override is null until an admin manually sets it;
|
|
31
|
+
// MikroORM returns null (never undefined) for nullable boolean columns
|
|
32
|
+
const shouldUpdateVisibility = existing.length === 0 ||
|
|
33
|
+
existing[0].visibility_override === null;
|
|
34
|
+
const data = {
|
|
35
|
+
printify_id: String(product.id),
|
|
36
|
+
shop_id: shopId,
|
|
37
|
+
title: product.title,
|
|
38
|
+
description: product.description,
|
|
39
|
+
variants: product.variants,
|
|
40
|
+
images: product.images,
|
|
41
|
+
print_areas: product.print_areas,
|
|
42
|
+
printify_data: product,
|
|
43
|
+
...(shouldUpdateVisibility ? { is_published: printifyPublished } : {}),
|
|
44
|
+
};
|
|
45
|
+
if (existing.length > 0) {
|
|
46
|
+
await service.updatePrintifyProducts({
|
|
47
|
+
selector: { printify_id: String(product.id) },
|
|
48
|
+
data,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
await service.createPrintifyProducts([data]);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return new workflows_sdk_1.StepResponse({ synced: products.length });
|
|
56
|
+
});
|
|
57
|
+
function slugify(text) {
|
|
58
|
+
return text
|
|
59
|
+
.toLowerCase()
|
|
60
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
61
|
+
.replace(/^-|-$/g, "");
|
|
62
|
+
}
|
|
63
|
+
function buildMedusaVariants(enabledVariants, mapped, printifyProductId, currencies, rates, existingVariantIdMap) {
|
|
64
|
+
return enabledVariants.map((v) => ({
|
|
65
|
+
...(existingVariantIdMap?.get(v.id) ? { id: existingVariantIdMap.get(v.id) } : {}),
|
|
66
|
+
title: v.title,
|
|
67
|
+
sku: v.sku || undefined,
|
|
68
|
+
options: mapped.variantOptionMap.get(v.id) ?? {},
|
|
69
|
+
prices: (0, build_variant_prices_1.buildVariantPrices)(v.price, currencies, rates),
|
|
70
|
+
manage_inventory: false,
|
|
71
|
+
metadata: {
|
|
72
|
+
printify_variant_id: v.id,
|
|
73
|
+
printify_product_id: printifyProductId,
|
|
74
|
+
},
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
async function associateVariantImages(productModuleService, medusaProductId, variantImageMap, logger) {
|
|
78
|
+
const product = await productModuleService.retrieveProduct(medusaProductId, {
|
|
79
|
+
relations: ["images", "variants"],
|
|
80
|
+
});
|
|
81
|
+
logger.info(`[printify] associateVariantImages: product ${medusaProductId} has ${product.images?.length ?? 0} images, ${product.variants?.length ?? 0} variants, variantImageMap has ${variantImageMap.size} entries`);
|
|
82
|
+
const urlToImageId = new Map();
|
|
83
|
+
for (const img of product.images ?? []) {
|
|
84
|
+
urlToImageId.set(img.url, img.id);
|
|
85
|
+
}
|
|
86
|
+
const pairs = [];
|
|
87
|
+
for (const variant of product.variants ?? []) {
|
|
88
|
+
const printifyVarId = variant.metadata?.printify_variant_id;
|
|
89
|
+
if (printifyVarId == null)
|
|
90
|
+
continue;
|
|
91
|
+
// Handle both number and string types from JSON round-trip
|
|
92
|
+
const numericId = typeof printifyVarId === "string" ? parseInt(printifyVarId, 10) : printifyVarId;
|
|
93
|
+
const imageUrls = variantImageMap.get(numericId);
|
|
94
|
+
if (!imageUrls?.length) {
|
|
95
|
+
logger.warn(`[printify] associateVariantImages: no images in variantImageMap for printify variant ${numericId}`);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
for (const { url } of imageUrls) {
|
|
99
|
+
const medusaImageId = urlToImageId.get(url);
|
|
100
|
+
if (medusaImageId) {
|
|
101
|
+
pairs.push({ image_id: medusaImageId, variant_id: variant.id });
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
logger.warn(`[printify] associateVariantImages: URL not found in Medusa images: ${url}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (pairs.length > 0) {
|
|
109
|
+
await productModuleService.addImageToVariant(pairs);
|
|
110
|
+
logger.info(`[printify] Associated ${pairs.length} variant-image pairs for product ${medusaProductId}`);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
logger.warn(`[printify] associateVariantImages: NO pairs created for product ${medusaProductId}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function extractPrintifyMappings(pp) {
|
|
117
|
+
const printifyData = pp.printify_data;
|
|
118
|
+
const printifyOptions = printifyData?.options ?? [];
|
|
119
|
+
const variants = pp.variants ?? [];
|
|
120
|
+
const printifyImages = pp.images ?? [];
|
|
121
|
+
const enabledVariants = variants.filter((v) => v.is_enabled);
|
|
122
|
+
const mapped = (0, option_mapper_1.mapPrintifyOptions)(printifyOptions, variants, printifyImages);
|
|
123
|
+
return { variants, enabledVariants, printifyImages, mapped };
|
|
124
|
+
}
|
|
125
|
+
const createMedusaProductsStep = (0, workflows_sdk_1.createStep)("printify-create-medusa-products-step", async ({ shopId, _upsertDone }, { container }) => {
|
|
126
|
+
const service = container.resolve(printify_1.PRINTIFY_MODULE);
|
|
127
|
+
const query = container.resolve(utils_1.ContainerRegistrationKeys.QUERY);
|
|
128
|
+
const link = container.resolve(utils_1.ContainerRegistrationKeys.LINK);
|
|
129
|
+
const productModuleService = container.resolve(utils_1.Modules.PRODUCT);
|
|
130
|
+
const logger = container.resolve(utils_1.ContainerRegistrationKeys.LOGGER);
|
|
131
|
+
// Get all published printify products for this shop
|
|
132
|
+
const printifyProducts = await service.listPrintifyProducts({
|
|
133
|
+
shop_id: shopId,
|
|
134
|
+
is_published: true,
|
|
135
|
+
});
|
|
136
|
+
if (printifyProducts.length === 0) {
|
|
137
|
+
return new workflows_sdk_1.StepResponse({ created: 0, updated: 0 });
|
|
138
|
+
}
|
|
139
|
+
// Resolve shipping profile (first available)
|
|
140
|
+
const fulfillmentService = container.resolve(utils_1.Modules.FULFILLMENT);
|
|
141
|
+
const shippingProfiles = await fulfillmentService.listShippingProfiles({});
|
|
142
|
+
if (shippingProfiles.length === 0) {
|
|
143
|
+
logger.warn("[printify] No shipping profiles found — skipping Medusa product creation");
|
|
144
|
+
return new workflows_sdk_1.StepResponse({ created: 0, updated: 0 });
|
|
145
|
+
}
|
|
146
|
+
const shippingProfileId = shippingProfiles[0].id;
|
|
147
|
+
// Resolve sales channel: shop setting → store default → skip
|
|
148
|
+
const shops = await service.listPrintifyShops({ printify_id: shopId });
|
|
149
|
+
let salesChannelId = shops[0]?.sales_channel_id ?? null;
|
|
150
|
+
if (!salesChannelId) {
|
|
151
|
+
const storeService = container.resolve(utils_1.Modules.STORE);
|
|
152
|
+
const stores = await storeService.listStores({});
|
|
153
|
+
salesChannelId = stores[0]?.default_sales_channel_id ?? null;
|
|
154
|
+
if (salesChannelId) {
|
|
155
|
+
logger.info(`[printify] Using store default sales channel: ${salesChannelId}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (!salesChannelId) {
|
|
159
|
+
logger.error(`[printify] PRODUCTS WILL NOT APPEAR ON STOREFRONT — no sales channel configured. ` +
|
|
160
|
+
`Set printify_shop.sales_channel_id via PATCH /admin/printify/shops/${shopId}, ` +
|
|
161
|
+
`or set a default_sales_channel_id on the store. ` +
|
|
162
|
+
`(${printifyProducts.length} published products waiting to sync)`);
|
|
163
|
+
return new workflows_sdk_1.StepResponse({ created: 0, updated: 0 });
|
|
164
|
+
}
|
|
165
|
+
// Fetch all unique currencies from active regions
|
|
166
|
+
const regionModule = container.resolve(utils_1.Modules.REGION);
|
|
167
|
+
const regions = await regionModule.listRegions({});
|
|
168
|
+
const currencies = [...new Set(regions.map((r) => r.currency_code))];
|
|
169
|
+
// Always include usd (Printify's base currency)
|
|
170
|
+
if (!currencies.includes("usd")) {
|
|
171
|
+
currencies.unshift("usd");
|
|
172
|
+
}
|
|
173
|
+
// Fetch exchange rates once for all products in this sync
|
|
174
|
+
let rates = {};
|
|
175
|
+
let ratesFetched = false;
|
|
176
|
+
if (currencies.length === 1 && currencies[0] === "usd") {
|
|
177
|
+
logger.info("[printify] Only USD region active — skipping exchange rate fetch");
|
|
178
|
+
ratesFetched = true;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
try {
|
|
182
|
+
rates = await (0, currency_converter_1.fetchExchangeRates)(currencies);
|
|
183
|
+
ratesFetched = true;
|
|
184
|
+
logger.info(`[printify] Fetched exchange rates for ${currencies.join(", ")}`);
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
logger.warn(`[printify] Could not fetch exchange rates — falling back to USD only: ${err instanceof Error ? err.message : err}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// If rates fetch failed, only create USD prices (for new products)
|
|
191
|
+
const activeCurrencies = ratesFetched ? currencies : ["usd"];
|
|
192
|
+
// When we need multi-currency pricing but rates are unavailable,
|
|
193
|
+
// avoid overwriting existing multi-currency prices on product updates
|
|
194
|
+
const hasCompletePricing = ratesFetched || currencies.length <= 1;
|
|
195
|
+
let created = 0;
|
|
196
|
+
let updated = 0;
|
|
197
|
+
for (const pp of printifyProducts) {
|
|
198
|
+
// Check if a linked Medusa product already exists
|
|
199
|
+
let medusaProductId = null;
|
|
200
|
+
try {
|
|
201
|
+
const { data } = await query.graph({
|
|
202
|
+
entity: "printify_product",
|
|
203
|
+
fields: ["product.id"],
|
|
204
|
+
filters: { id: pp.id },
|
|
205
|
+
});
|
|
206
|
+
if (data.length > 0 && data[0].product?.id) {
|
|
207
|
+
medusaProductId = data[0].product.id;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// Link query failed — treat as no link
|
|
212
|
+
}
|
|
213
|
+
const { enabledVariants, printifyImages, mapped } = extractPrintifyMappings(pp);
|
|
214
|
+
if (enabledVariants.length === 0) {
|
|
215
|
+
logger.warn(`[printify] Product "${pp.title}" has no enabled variants — skipping`);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (!mapped) {
|
|
219
|
+
logger.error(`[printify] Product "${pp.title}" (${pp.printify_id}) has no options in printify_data — skipping`);
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if (!medusaProductId) {
|
|
223
|
+
// Create a new Medusa product
|
|
224
|
+
try {
|
|
225
|
+
const { result } = await (0, core_flows_1.createProductsWorkflow)(container).run({
|
|
226
|
+
input: {
|
|
227
|
+
products: [
|
|
228
|
+
{
|
|
229
|
+
title: pp.title,
|
|
230
|
+
description: pp.description || undefined,
|
|
231
|
+
handle: slugify(pp.title),
|
|
232
|
+
status: "published",
|
|
233
|
+
images: printifyImages.map((img) => ({ url: img.src })),
|
|
234
|
+
options: mapped.medusaOptions,
|
|
235
|
+
variants: buildMedusaVariants(enabledVariants, mapped, pp.printify_id, activeCurrencies, rates),
|
|
236
|
+
sales_channels: [{ id: salesChannelId }],
|
|
237
|
+
shipping_profile_id: shippingProfileId,
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
const newProduct = result[0];
|
|
243
|
+
// Create module link: printify_product ↔ product
|
|
244
|
+
await link.create({
|
|
245
|
+
[printify_1.PRINTIFY_MODULE]: { printify_product_id: pp.id },
|
|
246
|
+
[utils_1.Modules.PRODUCT]: { product_id: newProduct.id },
|
|
247
|
+
});
|
|
248
|
+
await associateVariantImages(productModuleService, newProduct.id, mapped.variantImageMap, logger);
|
|
249
|
+
created++;
|
|
250
|
+
logger.info(`[printify] Created Medusa product "${pp.title}" (${newProduct.id})`);
|
|
251
|
+
}
|
|
252
|
+
catch (err) {
|
|
253
|
+
logger.error(`[printify] Failed to create Medusa product for "${pp.title}": ${err instanceof Error ? err.message : JSON.stringify(err)}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
// Update existing linked Medusa product
|
|
258
|
+
try {
|
|
259
|
+
const targetStatus = pp.is_published ? "published" : "draft";
|
|
260
|
+
// Build a map of existing Medusa variant IDs keyed by Printify variant ID
|
|
261
|
+
// so updateProducts can match existing variants instead of trying to create duplicates
|
|
262
|
+
const existingProduct = await productModuleService.retrieveProduct(medusaProductId, {
|
|
263
|
+
relations: ["variants"],
|
|
264
|
+
});
|
|
265
|
+
const existingVariantIdMap = new Map();
|
|
266
|
+
for (const variant of existingProduct.variants ?? []) {
|
|
267
|
+
const printifyVarId = variant.metadata?.printify_variant_id;
|
|
268
|
+
if (printifyVarId != null) {
|
|
269
|
+
const numericId = typeof printifyVarId === "string" ? parseInt(printifyVarId, 10) : printifyVarId;
|
|
270
|
+
existingVariantIdMap.set(numericId, variant.id);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (!hasCompletePricing) {
|
|
274
|
+
logger.warn(`[printify] Skipping variant/price update for "${pp.title}" — exchange rates unavailable, preserving existing multi-currency prices`);
|
|
275
|
+
}
|
|
276
|
+
await (0, core_flows_1.updateProductsWorkflow)(container).run({
|
|
277
|
+
input: {
|
|
278
|
+
products: [
|
|
279
|
+
{
|
|
280
|
+
id: medusaProductId,
|
|
281
|
+
title: pp.title,
|
|
282
|
+
description: pp.description || undefined,
|
|
283
|
+
status: targetStatus,
|
|
284
|
+
images: printifyImages.map((img) => ({ url: img.src })),
|
|
285
|
+
sales_channels: [{ id: salesChannelId }],
|
|
286
|
+
...(hasCompletePricing
|
|
287
|
+
? {
|
|
288
|
+
options: mapped.medusaOptions,
|
|
289
|
+
variants: buildMedusaVariants(enabledVariants, mapped, pp.printify_id, activeCurrencies, rates, existingVariantIdMap),
|
|
290
|
+
}
|
|
291
|
+
: {}),
|
|
292
|
+
},
|
|
293
|
+
],
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
await associateVariantImages(productModuleService, medusaProductId, mapped.variantImageMap, logger);
|
|
297
|
+
updated++;
|
|
298
|
+
logger.info(`[printify] Updated Medusa product "${pp.title}" (${medusaProductId})`);
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
logger.error(`[printify] Failed to update Medusa product ${medusaProductId}: ${err instanceof Error ? err.message : JSON.stringify(err)}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return new workflows_sdk_1.StepResponse({ created, updated });
|
|
306
|
+
});
|
|
307
|
+
exports.syncProductsWorkflow = (0, workflows_sdk_1.createWorkflow)("sync-printify-products", (input) => {
|
|
308
|
+
const products = fetchAllProductsStep(input);
|
|
309
|
+
const upsertResult = upsertProductsStep({ products, shopId: input.shopId });
|
|
310
|
+
const medusaResult = createMedusaProductsStep({ shopId: input.shopId, _upsertDone: upsertResult });
|
|
311
|
+
return new workflows_sdk_1.WorkflowResponse(medusaResult);
|
|
312
|
+
});
|
|
313
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1wcm9kdWN0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy93b3JrZmxvd3Mvc3luYy1wcm9kdWN0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxxRUFLMEM7QUFDMUMscURBQThFO0FBQzlFLDREQUE0RjtBQUU1RixrREFBcUQ7QUFHckQsbURBQW9EO0FBQ3BELG9FQUFvRjtBQUNwRix3RUFBa0U7QUFNbEUsTUFBTSxvQkFBb0IsR0FBRyxJQUFBLDBCQUFVLEVBQ3JDLGtDQUFrQyxFQUNsQyxLQUFLLEVBQUUsRUFBRSxNQUFNLEVBQXFCLEVBQUUsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFO0lBQ3JELE1BQU0sT0FBTyxHQUEwQixTQUFTLENBQUMsT0FBTyxDQUFDLDBCQUFlLENBQUMsQ0FBQTtJQUN6RSxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUE7SUFFckMsTUFBTSxRQUFRLEdBQXNCLEVBQUUsQ0FBQTtJQUN0QyxJQUFJLElBQUksR0FBRyxDQUFDLENBQUE7SUFDWixJQUFJLFFBQVEsR0FBRyxDQUFDLENBQUE7SUFFaEIsR0FBRyxDQUFDO1FBQ0YsTUFBTSxRQUFRLEdBQUcsTUFBTSxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUE7UUFDM0QsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUMvQixRQUFRLEdBQUcsUUFBUSxDQUFDLFNBQVMsQ0FBQTtRQUM3QixJQUFJLEVBQUUsQ0FBQTtJQUNSLENBQUMsUUFBUSxJQUFJLElBQUksUUFBUSxFQUFDO0lBRTFCLE9BQU8sSUFBSSw0QkFBWSxDQUFDLFFBQVEsQ0FBQyxDQUFBO0FBQ25DLENBQUMsQ0FDRixDQUFBO0FBRUQsTUFBTSxrQkFBa0IsR0FBRyxJQUFBLDBCQUFVLEVBQ25DLCtCQUErQixFQUMvQixLQUFLLEVB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
|