@reactionary/medusa 0.6.4 → 0.6.6
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/capabilities/cart.capability.js +7 -99
- package/capabilities/category.capability.js +29 -47
- package/capabilities/checkout.capability.js +19 -209
- package/capabilities/inventory.capability.js +10 -54
- package/capabilities/order-search.capability.js +2 -76
- package/capabilities/order.capability.js +2 -130
- package/capabilities/price.capability.js +3 -38
- package/capabilities/product-associations.capability.js +19 -54
- package/capabilities/product-search.capability.js +15 -67
- package/capabilities/product.capability.js +18 -131
- package/capabilities/profile.capability.js +14 -63
- package/factories/cart/cart.factory.js +91 -2
- package/factories/category/category.factory.js +33 -3
- package/factories/checkout/checkout.factory.js +187 -4
- package/factories/inventory/inventory.factory.js +19 -1
- package/factories/order/order.factory.js +128 -2
- package/factories/order-search/order-search.factory.js +75 -2
- package/factories/price/price.factory.js +31 -2
- package/factories/product/product.factory.js +155 -2
- package/factories/product-associations/product-associations.factory.js +38 -2
- package/factories/product-search/product-search.factory.js +51 -2
- package/factories/profile/profile.factory.js +54 -2
- package/package.json +2 -2
- package/src/capabilities/cart.capability.d.ts +2 -28
- package/src/capabilities/category.capability.d.ts +5 -7
- package/src/capabilities/checkout.capability.d.ts +3 -35
- package/src/capabilities/inventory.capability.d.ts +2 -12
- package/src/capabilities/order-search.capability.d.ts +2 -42
- package/src/capabilities/order.capability.d.ts +2 -39
- package/src/capabilities/price.capability.d.ts +1 -4
- package/src/capabilities/product-associations.capability.d.ts +3 -7
- package/src/capabilities/product-search.capability.d.ts +4 -34
- package/src/capabilities/product.capability.d.ts +1 -6
- package/src/capabilities/profile.capability.d.ts +3 -5
- package/src/factories/cart/cart.factory.d.ts +23 -2
- package/src/factories/category/category.factory.d.ts +4 -3
- package/src/factories/checkout/checkout.factory.d.ts +31 -4
- package/src/factories/inventory/inventory.factory.d.ts +7 -1
- package/src/factories/order/order.factory.d.ts +38 -2
- package/src/factories/order-search/order-search.factory.d.ts +20 -2
- package/src/factories/price/price.factory.d.ts +6 -1
- package/src/factories/product/product.factory.d.ts +6 -2
- package/src/factories/product-associations/product-associations.factory.d.ts +8 -2
- package/src/factories/product-search/product-search.factory.d.ts +5 -2
- package/src/factories/profile/profile.factory.d.ts +4 -2
|
@@ -4,7 +4,25 @@ class MedusaInventoryFactory {
|
|
|
4
4
|
this.inventorySchema = inventorySchema;
|
|
5
5
|
}
|
|
6
6
|
parseInventory(_context, data) {
|
|
7
|
-
|
|
7
|
+
const { sku, fulfillmentCenterKey, quantity } = data;
|
|
8
|
+
const identifier = {
|
|
9
|
+
variant: {
|
|
10
|
+
sku
|
|
11
|
+
},
|
|
12
|
+
fulfillmentCenter: {
|
|
13
|
+
key: fulfillmentCenterKey
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
let status = "outOfStock";
|
|
17
|
+
if (quantity > 0) {
|
|
18
|
+
status = "inStock";
|
|
19
|
+
}
|
|
20
|
+
const result = {
|
|
21
|
+
identifier,
|
|
22
|
+
quantity,
|
|
23
|
+
status
|
|
24
|
+
};
|
|
25
|
+
return this.inventorySchema.parse(result);
|
|
8
26
|
}
|
|
9
27
|
}
|
|
10
28
|
export {
|
|
@@ -1,10 +1,136 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ProductVariantIdentifierSchema
|
|
3
|
+
} from "@reactionary/core";
|
|
4
|
+
import { parseMedusaCostBreakdown, parseMedusaItemPrice } from "../../utils/medusa-helpers.js";
|
|
1
5
|
class MedusaOrderFactory {
|
|
2
6
|
orderSchema;
|
|
3
7
|
constructor(orderSchema) {
|
|
4
8
|
this.orderSchema = orderSchema;
|
|
5
9
|
}
|
|
6
|
-
parseOrder(
|
|
7
|
-
|
|
10
|
+
parseOrder(context, data) {
|
|
11
|
+
const identifier = { key: data.id };
|
|
12
|
+
const userId = {
|
|
13
|
+
userId: data.customer_id || ""
|
|
14
|
+
};
|
|
15
|
+
const items = (data.items || []).map((item) => {
|
|
16
|
+
return this.parseOrderItem(context, item, data.currency_code.toUpperCase());
|
|
17
|
+
});
|
|
18
|
+
const price = this.parseCostBreakdown(context, data);
|
|
19
|
+
let orderStatus = "AwaitingPayment";
|
|
20
|
+
if (data.status === "draft") {
|
|
21
|
+
orderStatus = "AwaitingPayment";
|
|
22
|
+
}
|
|
23
|
+
if (data.status === "pending") {
|
|
24
|
+
orderStatus = "ReleasedToFulfillment";
|
|
25
|
+
}
|
|
26
|
+
if (data.status === "completed") {
|
|
27
|
+
orderStatus = "Shipped";
|
|
28
|
+
}
|
|
29
|
+
if (data.status === "canceled") {
|
|
30
|
+
orderStatus = "Cancelled";
|
|
31
|
+
}
|
|
32
|
+
let inventoryStatus = "NotAllocated";
|
|
33
|
+
if (data.fulfillment_status === "fulfilled") {
|
|
34
|
+
inventoryStatus = "Allocated";
|
|
35
|
+
}
|
|
36
|
+
const paymentInstructions = data.payment_collections?.map((pc) => {
|
|
37
|
+
return this.parsePaymentInstruction(context, pc, data);
|
|
38
|
+
}) || [];
|
|
39
|
+
const result = {
|
|
40
|
+
identifier,
|
|
41
|
+
userId,
|
|
42
|
+
items,
|
|
43
|
+
price,
|
|
44
|
+
orderStatus,
|
|
45
|
+
inventoryStatus,
|
|
46
|
+
paymentInstructions
|
|
47
|
+
};
|
|
48
|
+
return this.orderSchema.parse(result);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Extension point to control the parsing of a single cart item price
|
|
52
|
+
* @param remoteItem
|
|
53
|
+
* @param currency
|
|
54
|
+
* @returns
|
|
55
|
+
*/
|
|
56
|
+
parseItemPrice(context, remoteItem, currency) {
|
|
57
|
+
return parseMedusaItemPrice(remoteItem, currency);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Extension point to control the parsing of the cost breakdown of a cart
|
|
61
|
+
* @param remote
|
|
62
|
+
* @returns
|
|
63
|
+
*/
|
|
64
|
+
parseCostBreakdown(_context, remote) {
|
|
65
|
+
return parseMedusaCostBreakdown(remote);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Extension point to control the parsing of a single cart item
|
|
69
|
+
* @param remoteItem
|
|
70
|
+
* @param currency
|
|
71
|
+
* @returns
|
|
72
|
+
*/
|
|
73
|
+
parseOrderItem(context, remoteItem, currency) {
|
|
74
|
+
const item = {
|
|
75
|
+
identifier: {
|
|
76
|
+
key: remoteItem.id
|
|
77
|
+
},
|
|
78
|
+
variant: ProductVariantIdentifierSchema.parse({
|
|
79
|
+
sku: remoteItem.variant_sku || ""
|
|
80
|
+
}),
|
|
81
|
+
quantity: remoteItem.quantity || 1,
|
|
82
|
+
price: this.parseItemPrice(context, remoteItem, currency),
|
|
83
|
+
inventoryStatus: "Allocated"
|
|
84
|
+
};
|
|
85
|
+
return item;
|
|
86
|
+
}
|
|
87
|
+
parsePaymentInstruction(_context, remotePayment, order) {
|
|
88
|
+
const paymentMethodIdentifier = {
|
|
89
|
+
method: remotePayment.payment_providers?.[0]?.id || "unknown",
|
|
90
|
+
name: remotePayment.payment_providers?.[0]?.id || "unknown",
|
|
91
|
+
paymentProcessor: remotePayment.payment_providers?.[0]?.id || "unknown"
|
|
92
|
+
};
|
|
93
|
+
let status = "pending";
|
|
94
|
+
switch (remotePayment.status) {
|
|
95
|
+
case "not_paid":
|
|
96
|
+
status = "pending";
|
|
97
|
+
break;
|
|
98
|
+
case "awaiting":
|
|
99
|
+
status = "pending";
|
|
100
|
+
break;
|
|
101
|
+
case "authorized":
|
|
102
|
+
status = "authorized";
|
|
103
|
+
break;
|
|
104
|
+
case "partially_authorized":
|
|
105
|
+
status = "pending";
|
|
106
|
+
break;
|
|
107
|
+
case "canceled":
|
|
108
|
+
status = "canceled";
|
|
109
|
+
break;
|
|
110
|
+
case "failed":
|
|
111
|
+
status = "canceled";
|
|
112
|
+
break;
|
|
113
|
+
case "completed":
|
|
114
|
+
status = "capture";
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
const paymentData = remotePayment.payments?.[0].data || {};
|
|
118
|
+
const pi = {
|
|
119
|
+
identifier: {
|
|
120
|
+
key: remotePayment.id
|
|
121
|
+
},
|
|
122
|
+
amount: {
|
|
123
|
+
value: remotePayment.amount,
|
|
124
|
+
currency: remotePayment.currency_code?.toUpperCase()
|
|
125
|
+
},
|
|
126
|
+
paymentMethod: paymentMethodIdentifier,
|
|
127
|
+
protocolData: paymentData ? Object.entries(paymentData).map(([key, value]) => ({
|
|
128
|
+
key,
|
|
129
|
+
value: String(value)
|
|
130
|
+
})) : [],
|
|
131
|
+
status
|
|
132
|
+
};
|
|
133
|
+
return pi;
|
|
8
134
|
}
|
|
9
135
|
}
|
|
10
136
|
export {
|
|
@@ -1,10 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AddressIdentifierSchema
|
|
3
|
+
} from "@reactionary/core";
|
|
1
4
|
class MedusaOrderSearchFactory {
|
|
2
5
|
orderSearchResultSchema;
|
|
3
6
|
constructor(orderSearchResultSchema) {
|
|
4
7
|
this.orderSearchResultSchema = orderSearchResultSchema;
|
|
5
8
|
}
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
parseOrderSearchResultItem(context, body) {
|
|
10
|
+
const identifier = { key: body.id };
|
|
11
|
+
const userId = {
|
|
12
|
+
userId: body.customer_id || ""
|
|
13
|
+
};
|
|
14
|
+
const customerName = `${body.billing_address?.first_name} ${body.billing_address?.last_name}`;
|
|
15
|
+
const shippingAddress = this.parseAddress(context, body.shipping_address);
|
|
16
|
+
const orderDate = new Date(body.created_at).toISOString();
|
|
17
|
+
let orderStatus = "AwaitingPayment";
|
|
18
|
+
if (body.status === "draft") {
|
|
19
|
+
orderStatus = "AwaitingPayment";
|
|
20
|
+
}
|
|
21
|
+
if (body.status === "pending") {
|
|
22
|
+
orderStatus = "ReleasedToFulfillment";
|
|
23
|
+
}
|
|
24
|
+
if (body.status === "completed") {
|
|
25
|
+
orderStatus = "Shipped";
|
|
26
|
+
}
|
|
27
|
+
if (body.status === "canceled") {
|
|
28
|
+
orderStatus = "Cancelled";
|
|
29
|
+
}
|
|
30
|
+
let inventoryStatus = "NotAllocated";
|
|
31
|
+
if (body.fulfillment_status === "fulfilled") {
|
|
32
|
+
inventoryStatus = "Allocated";
|
|
33
|
+
}
|
|
34
|
+
const totalAmount = {
|
|
35
|
+
currency: body.currency_code.toUpperCase(),
|
|
36
|
+
value: body.total ? body.total : 0
|
|
37
|
+
};
|
|
38
|
+
const order = {
|
|
39
|
+
identifier,
|
|
40
|
+
userId,
|
|
41
|
+
customerName,
|
|
42
|
+
shippingAddress,
|
|
43
|
+
orderDate,
|
|
44
|
+
orderStatus,
|
|
45
|
+
inventoryStatus,
|
|
46
|
+
totalAmount
|
|
47
|
+
};
|
|
48
|
+
return order;
|
|
49
|
+
}
|
|
50
|
+
parseAddress(_context, storeAddress) {
|
|
51
|
+
return {
|
|
52
|
+
identifier: AddressIdentifierSchema.parse({
|
|
53
|
+
nickName: storeAddress.id
|
|
54
|
+
}),
|
|
55
|
+
firstName: storeAddress.first_name || "",
|
|
56
|
+
lastName: storeAddress.last_name || "",
|
|
57
|
+
streetAddress: storeAddress.address_1 || "",
|
|
58
|
+
streetNumber: storeAddress.address_2 || "",
|
|
59
|
+
city: storeAddress.city || "",
|
|
60
|
+
postalCode: storeAddress.postal_code || "",
|
|
61
|
+
countryCode: storeAddress.country_code || "",
|
|
62
|
+
region: ""
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
parseOrderSearchResult(_context, data, query) {
|
|
66
|
+
const identifier = {
|
|
67
|
+
...query.search
|
|
68
|
+
};
|
|
69
|
+
const orders = data.orders.map((o) => {
|
|
70
|
+
return this.parseOrderSearchResultItem(_context, o);
|
|
71
|
+
});
|
|
72
|
+
const result = {
|
|
73
|
+
identifier,
|
|
74
|
+
pageNumber: (Math.ceil(data.offset / data.limit) || 0) + 1,
|
|
75
|
+
pageSize: data.limit,
|
|
76
|
+
totalCount: data.count,
|
|
77
|
+
totalPages: Math.ceil(data.count / data.limit || 0) + 1,
|
|
78
|
+
items: orders
|
|
79
|
+
};
|
|
80
|
+
return this.orderSearchResultSchema.parse(result);
|
|
8
81
|
}
|
|
9
82
|
}
|
|
10
83
|
export {
|
|
@@ -3,8 +3,37 @@ class MedusaPriceFactory {
|
|
|
3
3
|
constructor(priceSchema) {
|
|
4
4
|
this.priceSchema = priceSchema;
|
|
5
5
|
}
|
|
6
|
-
parsePrice(
|
|
7
|
-
|
|
6
|
+
parsePrice(context, data, _options) {
|
|
7
|
+
const identifier = {
|
|
8
|
+
variant: {
|
|
9
|
+
sku: data.variant.sku || ""
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const calculatedPrice = data.variant.calculated_price;
|
|
13
|
+
let unitPrice;
|
|
14
|
+
let isOnSale = false;
|
|
15
|
+
if (calculatedPrice) {
|
|
16
|
+
const priceToUse = data.mode === "customer" ? calculatedPrice.calculated_amount : calculatedPrice.original_amount;
|
|
17
|
+
if (data.mode === "customer") {
|
|
18
|
+
isOnSale = calculatedPrice.calculated_price?.price_list_type === "sale";
|
|
19
|
+
}
|
|
20
|
+
unitPrice = {
|
|
21
|
+
value: priceToUse || 0,
|
|
22
|
+
currency: calculatedPrice.currency_code?.toUpperCase() || context.languageContext.currencyCode
|
|
23
|
+
};
|
|
24
|
+
} else {
|
|
25
|
+
unitPrice = {
|
|
26
|
+
value: -1,
|
|
27
|
+
currency: context.languageContext.currencyCode
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const result = {
|
|
31
|
+
identifier,
|
|
32
|
+
tieredPrices: [],
|
|
33
|
+
unitPrice,
|
|
34
|
+
onSale: isOnSale
|
|
35
|
+
};
|
|
36
|
+
return this.priceSchema.parse(result);
|
|
8
37
|
}
|
|
9
38
|
}
|
|
10
39
|
export {
|
|
@@ -1,10 +1,163 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CategoryIdentifierSchema,
|
|
3
|
+
ProductIdentifierSchema
|
|
4
|
+
} from "@reactionary/core";
|
|
5
|
+
import createDebug from "debug";
|
|
6
|
+
const debug = createDebug("reactionary:medusa:product");
|
|
1
7
|
class MedusaProductFactory {
|
|
2
8
|
productSchema;
|
|
3
9
|
constructor(productSchema) {
|
|
4
10
|
this.productSchema = productSchema;
|
|
5
11
|
}
|
|
6
|
-
|
|
7
|
-
|
|
12
|
+
parseVariant(_context, variant, product) {
|
|
13
|
+
const options = (variant.options ?? []).map((option) => {
|
|
14
|
+
const optionId = { key: option.option_id || "" };
|
|
15
|
+
const title = option.option?.title || "?";
|
|
16
|
+
const valueIdentifier = {
|
|
17
|
+
key: option.option_id || "",
|
|
18
|
+
option: optionId
|
|
19
|
+
};
|
|
20
|
+
const value = option.value || "";
|
|
21
|
+
const result2 = {
|
|
22
|
+
identifier: optionId,
|
|
23
|
+
name: title,
|
|
24
|
+
value: {
|
|
25
|
+
identifier: valueIdentifier,
|
|
26
|
+
label: value
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
return result2;
|
|
30
|
+
});
|
|
31
|
+
const result = {
|
|
32
|
+
identifier: {
|
|
33
|
+
sku: variant.sku || ""
|
|
34
|
+
},
|
|
35
|
+
name: variant.title || product.title,
|
|
36
|
+
upc: variant.upc || "",
|
|
37
|
+
ean: variant.ean || "",
|
|
38
|
+
images: (product.images || []).map((img) => {
|
|
39
|
+
return {
|
|
40
|
+
sourceUrl: img.url,
|
|
41
|
+
altText: variant.title || product.title || ""
|
|
42
|
+
};
|
|
43
|
+
}),
|
|
44
|
+
options,
|
|
45
|
+
gtin: variant.ean || "",
|
|
46
|
+
barcode: variant.ean || ""
|
|
47
|
+
};
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
createSynthAttribute(key, name, value) {
|
|
51
|
+
const attributeIdentifier = { key };
|
|
52
|
+
const valueIdentifier = {
|
|
53
|
+
key: `${key}-${value}`
|
|
54
|
+
};
|
|
55
|
+
const attribute = {
|
|
56
|
+
identifier: attributeIdentifier,
|
|
57
|
+
name,
|
|
58
|
+
group: "",
|
|
59
|
+
values: [
|
|
60
|
+
{
|
|
61
|
+
identifier: valueIdentifier,
|
|
62
|
+
label: String(value),
|
|
63
|
+
value
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
};
|
|
67
|
+
return attribute;
|
|
68
|
+
}
|
|
69
|
+
parseAttributes(_context, _body) {
|
|
70
|
+
const sharedAttributes = [];
|
|
71
|
+
if (_body.origin_country) {
|
|
72
|
+
sharedAttributes.push(
|
|
73
|
+
this.createSynthAttribute(
|
|
74
|
+
"origin_country",
|
|
75
|
+
"Origin Country",
|
|
76
|
+
_body.origin_country
|
|
77
|
+
)
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
if (_body.height) {
|
|
81
|
+
sharedAttributes.push(
|
|
82
|
+
this.createSynthAttribute("height", "Height", String(_body.height))
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
if (_body.weight) {
|
|
86
|
+
sharedAttributes.push(
|
|
87
|
+
this.createSynthAttribute("weight", "Weight", String(_body.weight))
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
if (_body.length) {
|
|
91
|
+
sharedAttributes.push(
|
|
92
|
+
this.createSynthAttribute("length", "Length", String(_body.length))
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (_body.width) {
|
|
96
|
+
sharedAttributes.push(
|
|
97
|
+
this.createSynthAttribute("width", "Width", String(_body.width))
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
if (_body.material) {
|
|
101
|
+
sharedAttributes.push(
|
|
102
|
+
this.createSynthAttribute("material", "Material", _body.material)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
if (_body.metadata) {
|
|
106
|
+
const keysToExclude = [
|
|
107
|
+
"reactionaryaccessories",
|
|
108
|
+
"reactionaryreplacements",
|
|
109
|
+
"reactionaryspareparts"
|
|
110
|
+
];
|
|
111
|
+
for (const [key, value] of Object.entries(_body.metadata)) {
|
|
112
|
+
if (keysToExclude.includes(key)) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
sharedAttributes.push(
|
|
116
|
+
this.createSynthAttribute(key, key, String(value))
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return sharedAttributes;
|
|
121
|
+
}
|
|
122
|
+
parseProduct(context, data) {
|
|
123
|
+
const identifier = ProductIdentifierSchema.parse({
|
|
124
|
+
key: data.external_id || data.id
|
|
125
|
+
});
|
|
126
|
+
const name = data.title;
|
|
127
|
+
const slug = data.handle;
|
|
128
|
+
const description = data.description || "" || data.subtitle || "";
|
|
129
|
+
const parentCategories = [];
|
|
130
|
+
parentCategories.push(
|
|
131
|
+
...data.categories?.map((cat) => cat.metadata?.["external_id"]).map((id) => CategoryIdentifierSchema.parse({ key: id || "" })) || []
|
|
132
|
+
);
|
|
133
|
+
const sharedAttributes = this.parseAttributes(context, data);
|
|
134
|
+
if (!data.variants) {
|
|
135
|
+
debug("Product has no variants", data);
|
|
136
|
+
throw new Error("Product has no variants " + data.external_id);
|
|
137
|
+
}
|
|
138
|
+
const mainVariant = this.parseVariant(context, data.variants[0], data);
|
|
139
|
+
const otherVariants = [];
|
|
140
|
+
if (data.variants.length > 1) {
|
|
141
|
+
otherVariants.push(
|
|
142
|
+
...data.variants.slice(1).map((variant) => this.parseVariant(context, variant, data))
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
const result = {
|
|
146
|
+
brand: "",
|
|
147
|
+
description,
|
|
148
|
+
identifier,
|
|
149
|
+
longDescription: "",
|
|
150
|
+
mainVariant,
|
|
151
|
+
manufacturer: "",
|
|
152
|
+
name,
|
|
153
|
+
options: [],
|
|
154
|
+
parentCategories,
|
|
155
|
+
published: true,
|
|
156
|
+
sharedAttributes,
|
|
157
|
+
slug,
|
|
158
|
+
variants: otherVariants
|
|
159
|
+
};
|
|
160
|
+
return this.productSchema.parse(result);
|
|
8
161
|
}
|
|
9
162
|
}
|
|
10
163
|
export {
|
|
@@ -1,10 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ImageSchema,
|
|
3
|
+
ProductSearchResultItemVariantSchema,
|
|
4
|
+
ProductVariantIdentifierSchema
|
|
5
|
+
} from "@reactionary/core";
|
|
1
6
|
class MedusaProductAssociationsFactory {
|
|
2
7
|
productAssociationSchema;
|
|
3
8
|
constructor(productAssociationSchema) {
|
|
4
9
|
this.productAssociationSchema = productAssociationSchema;
|
|
5
10
|
}
|
|
6
|
-
parseAssociation(
|
|
7
|
-
|
|
11
|
+
parseAssociation(context, data) {
|
|
12
|
+
const heroVariant = data.product.variants?.[0];
|
|
13
|
+
const identifier = { key: data.product.external_id || data.product.id };
|
|
14
|
+
const slug = data.product.handle;
|
|
15
|
+
const name = heroVariant?.title || data.product.title;
|
|
16
|
+
const variants = [];
|
|
17
|
+
if (heroVariant) {
|
|
18
|
+
variants.push(this.parseVariant(context, heroVariant, data.product));
|
|
19
|
+
}
|
|
20
|
+
const searchItemResult = {
|
|
21
|
+
identifier,
|
|
22
|
+
name,
|
|
23
|
+
slug,
|
|
24
|
+
variants
|
|
25
|
+
};
|
|
26
|
+
const result = {
|
|
27
|
+
associationIdentifier: data.identifier,
|
|
28
|
+
associationReturnType: "productSearchResultItem",
|
|
29
|
+
product: searchItemResult
|
|
30
|
+
};
|
|
31
|
+
return this.productAssociationSchema.parse(result);
|
|
32
|
+
}
|
|
33
|
+
parseVariant(_context, variant, product) {
|
|
34
|
+
const img = ImageSchema.parse({
|
|
35
|
+
sourceUrl: product.images?.[0].url ?? "",
|
|
36
|
+
altText: product.title || void 0
|
|
37
|
+
});
|
|
38
|
+
return ProductSearchResultItemVariantSchema.parse({
|
|
39
|
+
variant: ProductVariantIdentifierSchema.parse({
|
|
40
|
+
sku: variant.sku || ""
|
|
41
|
+
}),
|
|
42
|
+
image: img
|
|
43
|
+
});
|
|
8
44
|
}
|
|
9
45
|
}
|
|
10
46
|
export {
|
|
@@ -1,10 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ImageSchema,
|
|
3
|
+
ProductSearchResultItemVariantSchema,
|
|
4
|
+
ProductVariantIdentifierSchema
|
|
5
|
+
} from "@reactionary/core";
|
|
1
6
|
class MedusaProductSearchFactory {
|
|
2
7
|
productSearchResultSchema;
|
|
3
8
|
constructor(productSearchResultSchema) {
|
|
4
9
|
this.productSearchResultSchema = productSearchResultSchema;
|
|
5
10
|
}
|
|
6
|
-
parseSearchResult(
|
|
7
|
-
|
|
11
|
+
parseSearchResult(context, remote, query) {
|
|
12
|
+
const products = remote.products.map(
|
|
13
|
+
(p) => this.parseProductSearchResultItem(context, p)
|
|
14
|
+
);
|
|
15
|
+
const result = {
|
|
16
|
+
identifier: {
|
|
17
|
+
...query.search
|
|
18
|
+
},
|
|
19
|
+
pageNumber: (Math.ceil(remote.offset / remote.limit) || 0) + 1,
|
|
20
|
+
pageSize: remote.limit,
|
|
21
|
+
totalCount: remote.count,
|
|
22
|
+
totalPages: Math.ceil(remote.count / remote.limit || 0) + 1,
|
|
23
|
+
items: products,
|
|
24
|
+
facets: []
|
|
25
|
+
};
|
|
26
|
+
result.facets = [];
|
|
27
|
+
return this.productSearchResultSchema.parse(result);
|
|
28
|
+
}
|
|
29
|
+
parseProductSearchResultItem(context, data) {
|
|
30
|
+
const heroVariant = data.variants?.[0];
|
|
31
|
+
const identifier = { key: data.external_id || data.id };
|
|
32
|
+
const slug = data.handle;
|
|
33
|
+
const name = heroVariant?.title || data.title;
|
|
34
|
+
const variants = [];
|
|
35
|
+
if (heroVariant) {
|
|
36
|
+
variants.push(this.parseVariant(context, heroVariant, data));
|
|
37
|
+
}
|
|
38
|
+
const result = {
|
|
39
|
+
identifier,
|
|
40
|
+
name,
|
|
41
|
+
slug,
|
|
42
|
+
variants
|
|
43
|
+
};
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
parseVariant(_context, variant, product) {
|
|
47
|
+
const img = ImageSchema.parse({
|
|
48
|
+
sourceUrl: product.images?.[0].url ?? "",
|
|
49
|
+
altText: product.title || void 0
|
|
50
|
+
});
|
|
51
|
+
return ProductSearchResultItemVariantSchema.parse({
|
|
52
|
+
variant: ProductVariantIdentifierSchema.parse({
|
|
53
|
+
sku: variant.sku || ""
|
|
54
|
+
}),
|
|
55
|
+
image: img
|
|
56
|
+
});
|
|
8
57
|
}
|
|
9
58
|
}
|
|
10
59
|
export {
|
|
@@ -3,8 +3,60 @@ class MedusaProfileFactory {
|
|
|
3
3
|
constructor(profileSchema) {
|
|
4
4
|
this.profileSchema = profileSchema;
|
|
5
5
|
}
|
|
6
|
-
parseProfile(
|
|
7
|
-
|
|
6
|
+
parseProfile(context, data) {
|
|
7
|
+
const email = data.email;
|
|
8
|
+
const emailVerified = data.metadata?.["email_verified"] === "true";
|
|
9
|
+
const phone = data.phone || "";
|
|
10
|
+
const phoneVerified = data.metadata?.["phone_verified"] === "true";
|
|
11
|
+
const addresses = data.addresses || [];
|
|
12
|
+
let billingAddress = void 0;
|
|
13
|
+
let shippingAddress = void 0;
|
|
14
|
+
const existingBillingAddress = data.addresses.find(
|
|
15
|
+
(addr) => addr.is_default_billing
|
|
16
|
+
);
|
|
17
|
+
if (existingBillingAddress) {
|
|
18
|
+
billingAddress = this.parseAddress(context, existingBillingAddress);
|
|
19
|
+
}
|
|
20
|
+
const existingShippingAddress = data.addresses.find(
|
|
21
|
+
(addr) => addr.is_default_shipping
|
|
22
|
+
);
|
|
23
|
+
if (existingShippingAddress) {
|
|
24
|
+
shippingAddress = this.parseAddress(context, existingShippingAddress);
|
|
25
|
+
}
|
|
26
|
+
const alternateShippingAddresses = [];
|
|
27
|
+
alternateShippingAddresses.push(
|
|
28
|
+
...addresses.filter((x) => !(x.is_default_billing || x.is_default_shipping)).map((addr) => this.parseAddress(context, addr))
|
|
29
|
+
);
|
|
30
|
+
const result = {
|
|
31
|
+
identifier: {
|
|
32
|
+
userId: data.id
|
|
33
|
+
},
|
|
34
|
+
email,
|
|
35
|
+
emailVerified,
|
|
36
|
+
phone,
|
|
37
|
+
phoneVerified,
|
|
38
|
+
billingAddress,
|
|
39
|
+
shippingAddress,
|
|
40
|
+
alternateShippingAddresses,
|
|
41
|
+
createdAt: new Date(data.created_at || "").toISOString(),
|
|
42
|
+
updatedAt: new Date(data.updated_at || "").toISOString()
|
|
43
|
+
};
|
|
44
|
+
return this.profileSchema.parse(result);
|
|
45
|
+
}
|
|
46
|
+
parseAddress(context, address) {
|
|
47
|
+
return {
|
|
48
|
+
identifier: {
|
|
49
|
+
nickName: address.address_name || ""
|
|
50
|
+
},
|
|
51
|
+
firstName: address.first_name || "",
|
|
52
|
+
lastName: address.last_name || "",
|
|
53
|
+
streetAddress: address.address_1 || "",
|
|
54
|
+
streetNumber: address.address_2 || "",
|
|
55
|
+
city: address.city || "",
|
|
56
|
+
region: address.province || "",
|
|
57
|
+
postalCode: address.postal_code || "",
|
|
58
|
+
countryCode: address.country_code || ""
|
|
59
|
+
};
|
|
8
60
|
}
|
|
9
61
|
}
|
|
10
62
|
export {
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactionary/medusa",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@medusajs/js-sdk": "^2.13.3",
|
|
9
|
-
"@reactionary/core": "0.6.
|
|
9
|
+
"@reactionary/core": "0.6.6",
|
|
10
10
|
"debug": "^4.4.3",
|
|
11
11
|
"@medusajs/types": "^2.13.3",
|
|
12
12
|
"zod": "4.1.9",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { Cache,
|
|
1
|
+
import type { Cache, CartFactory, CartFactoryCartOutput, CartFactoryIdentifierOutput, CartFactoryWithOutput, CartMutationApplyCoupon, CartMutationChangeCurrency, CartMutationDeleteCart, CartMutationItemAdd, CartMutationItemQuantityChange, CartMutationItemRemove, CartMutationRemoveCoupon, CartQueryById, NotFoundError, RequestContext, Result } from '@reactionary/core';
|
|
2
2
|
import { CartCapability } from '@reactionary/core';
|
|
3
3
|
import type { MedusaAPI } from '../core/client.js';
|
|
4
4
|
import type { MedusaConfiguration } from '../schema/configuration.schema.js';
|
|
5
|
-
import type { StoreAddCartLineItem,
|
|
5
|
+
import type { StoreAddCartLineItem, StoreCartAddPromotion, StoreCartRemovePromotion, StoreCreateCart, StoreUpdateCart, StoreUpdateCartLineItem } from '@medusajs/types';
|
|
6
6
|
import type { MedusaCartFactory } from '../factories/cart/cart.factory.js';
|
|
7
7
|
export declare class MedusaCartCapability<TFactory extends CartFactory = MedusaCartFactory> extends CartCapability<CartFactoryCartOutput<TFactory>, CartFactoryIdentifierOutput<TFactory>> {
|
|
8
8
|
medusaApi: MedusaAPI;
|
|
@@ -71,30 +71,4 @@ export declare class MedusaCartCapability<TFactory extends CartFactory = MedusaC
|
|
|
71
71
|
store: import("@medusajs/js-sdk").Store;
|
|
72
72
|
auth: import("@medusajs/js-sdk").Auth;
|
|
73
73
|
}>;
|
|
74
|
-
/**
|
|
75
|
-
* Extension point to control the parsing of a single cart item price
|
|
76
|
-
* @param remoteItem
|
|
77
|
-
* @param currency
|
|
78
|
-
* @returns
|
|
79
|
-
*/
|
|
80
|
-
protected parseItemPrice(remoteItem: StoreCartLineItem, currency: Currency): ItemCostBreakdown;
|
|
81
|
-
/**
|
|
82
|
-
* Extension point to control the parsing of the cost breakdown of a cart
|
|
83
|
-
* @param remote
|
|
84
|
-
* @returns
|
|
85
|
-
*/
|
|
86
|
-
protected parseCostBreakdown(remote: StoreCart): CostBreakDown;
|
|
87
|
-
/**
|
|
88
|
-
* Extension point to control the parsing of a single cart item
|
|
89
|
-
* @param remoteItem
|
|
90
|
-
* @param currency
|
|
91
|
-
* @returns
|
|
92
|
-
*/
|
|
93
|
-
protected parseCartItem(remoteItem: StoreCartLineItem, currency: Currency): CartItem;
|
|
94
|
-
/**
|
|
95
|
-
* Extension point to control the parsing of a single cart
|
|
96
|
-
* @param remote
|
|
97
|
-
* @returns
|
|
98
|
-
*/
|
|
99
|
-
protected parseSingle(remote: StoreCart): CartFactoryCartOutput<TFactory>;
|
|
100
74
|
}
|