@porulle/adapter-shopify 0.76.0 → 0.77.1
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/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/webhooks.js +24 -1
- package/package.json +2 -2
- package/src/webhooks.ts +25 -1
package/dist/webhooks.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Err, Ok } from "@porulle/core";
|
|
1
|
+
import { Err, Ok, toMinorUnits } from "@porulle/core";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { shopifyGid, shopifyGraphql } from "./graphql.js";
|
|
4
4
|
/**
|
|
@@ -14,6 +14,7 @@ const inventoryItemVariantSchema = z.object({
|
|
|
14
14
|
const id = z.union([z.string(), z.number()]).transform(String);
|
|
15
15
|
const withId = z.object({ id });
|
|
16
16
|
const inventoryLevelPayload = z.object({ inventory_item_id: id });
|
|
17
|
+
const decimal = z.union([z.string(), z.number()]).transform(String);
|
|
17
18
|
const refundPayload = z.object({
|
|
18
19
|
id,
|
|
19
20
|
order_id: id,
|
|
@@ -21,7 +22,28 @@ const refundPayload = z.object({
|
|
|
21
22
|
quantity: z.number().int(),
|
|
22
23
|
line_item: z.object({ variant_id: id.nullish(), product_id: id.nullish() }),
|
|
23
24
|
})).default([]),
|
|
25
|
+
/** The money the refund moved. Absent from payloads that predate it; an empty list refunded nothing. */
|
|
26
|
+
transactions: z.array(z.object({ kind: z.string(), status: z.string().nullish(), amount: decimal, currency: z.string().nullish() })).optional(),
|
|
27
|
+
refund_shipping_lines: z.array(z.object({
|
|
28
|
+
subtotal_amount_set: z.object({ shop_money: z.object({ amount: decimal, currency_code: z.string() }) }),
|
|
29
|
+
})).default([]),
|
|
24
30
|
});
|
|
31
|
+
/**
|
|
32
|
+
* What a Shopify refund paid back: its successful refund transactions (an order paid on the
|
|
33
|
+
* marketplace refunds through the `manual` gateway), and of that the delivery, from
|
|
34
|
+
* `refund_shipping_lines` (present on every payload of the pinned API version).
|
|
35
|
+
*/
|
|
36
|
+
function refundMoney(refund) {
|
|
37
|
+
const currency = refund.transactions?.find((transaction) => transaction.currency)?.currency
|
|
38
|
+
?? refund.refund_shipping_lines[0]?.subtotal_amount_set.shop_money.currency_code;
|
|
39
|
+
// Money with no currency cannot be read in minor units; counted as nothing, it can only under-ask.
|
|
40
|
+
const minor = (value) => (currency ? Math.abs(toMinorUnits(value, currency) ?? 0) : 0);
|
|
41
|
+
const amount = refund.transactions === undefined
|
|
42
|
+
? undefined
|
|
43
|
+
: refund.transactions.filter((transaction) => transaction.kind.toLowerCase() === "refund" && (transaction.status ?? "success").toLowerCase() === "success").reduce((sum, transaction) => sum + minor(transaction.amount), 0);
|
|
44
|
+
const shippingAmount = refund.refund_shipping_lines.reduce((sum, line) => sum + minor(line.subtotal_amount_set.shop_money.amount), 0);
|
|
45
|
+
return { ...(amount === undefined ? {} : { amount }), ...(shippingAmount > 0 ? { shippingAmount } : {}) };
|
|
46
|
+
}
|
|
25
47
|
const fulfilledPayload = z.object({
|
|
26
48
|
id,
|
|
27
49
|
fulfillments: z.array(z.object({
|
|
@@ -109,6 +131,7 @@ export async function decodeShopifyWebhook(shop, event) {
|
|
|
109
131
|
const externalVariantId = entry.line_item.variant_id ?? entry.line_item.product_id;
|
|
110
132
|
return externalVariantId == null ? [] : [{ externalVariantId, quantity: entry.quantity }];
|
|
111
133
|
}),
|
|
134
|
+
...refundMoney(parsed.data),
|
|
112
135
|
}]);
|
|
113
136
|
}
|
|
114
137
|
const returnStatus = RETURN_STATUS[topic];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@porulle/adapter-shopify",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.77.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"zod": "^4.1.11",
|
|
19
|
-
"@porulle/core": "0.
|
|
19
|
+
"@porulle/core": "0.77.1"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/node": "^24.5.2",
|
package/src/webhooks.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Err, Ok } from "@porulle/core";
|
|
1
|
+
import { Err, Ok, toMinorUnits } from "@porulle/core";
|
|
2
2
|
import type { ChannelConnectorError, ChannelEvent, ChannelShipment, ChannelWebhookEvent, Result } from "@porulle/core";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { shopifyGid, shopifyGraphql } from "./graphql.js";
|
|
@@ -19,6 +19,7 @@ const inventoryItemVariantSchema = z.object({
|
|
|
19
19
|
const id = z.union([z.string(), z.number()]).transform(String);
|
|
20
20
|
const withId = z.object({ id });
|
|
21
21
|
const inventoryLevelPayload = z.object({ inventory_item_id: id });
|
|
22
|
+
const decimal = z.union([z.string(), z.number()]).transform(String);
|
|
22
23
|
const refundPayload = z.object({
|
|
23
24
|
id,
|
|
24
25
|
order_id: id,
|
|
@@ -26,7 +27,29 @@ const refundPayload = z.object({
|
|
|
26
27
|
quantity: z.number().int(),
|
|
27
28
|
line_item: z.object({ variant_id: id.nullish(), product_id: id.nullish() }),
|
|
28
29
|
})).default([]),
|
|
30
|
+
/** The money the refund moved. Absent from payloads that predate it; an empty list refunded nothing. */
|
|
31
|
+
transactions: z.array(z.object({ kind: z.string(), status: z.string().nullish(), amount: decimal, currency: z.string().nullish() })).optional(),
|
|
32
|
+
refund_shipping_lines: z.array(z.object({
|
|
33
|
+
subtotal_amount_set: z.object({ shop_money: z.object({ amount: decimal, currency_code: z.string() }) }),
|
|
34
|
+
})).default([]),
|
|
29
35
|
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* What a Shopify refund paid back: its successful refund transactions (an order paid on the
|
|
39
|
+
* marketplace refunds through the `manual` gateway), and of that the delivery, from
|
|
40
|
+
* `refund_shipping_lines` (present on every payload of the pinned API version).
|
|
41
|
+
*/
|
|
42
|
+
function refundMoney(refund: z.infer<typeof refundPayload>): { amount?: number; shippingAmount?: number } {
|
|
43
|
+
const currency = refund.transactions?.find((transaction) => transaction.currency)?.currency
|
|
44
|
+
?? refund.refund_shipping_lines[0]?.subtotal_amount_set.shop_money.currency_code;
|
|
45
|
+
// Money with no currency cannot be read in minor units; counted as nothing, it can only under-ask.
|
|
46
|
+
const minor = (value: string): number => (currency ? Math.abs(toMinorUnits(value, currency) ?? 0) : 0);
|
|
47
|
+
const amount = refund.transactions === undefined
|
|
48
|
+
? undefined
|
|
49
|
+
: refund.transactions.filter((transaction) => transaction.kind.toLowerCase() === "refund" && (transaction.status ?? "success").toLowerCase() === "success").reduce((sum, transaction) => sum + minor(transaction.amount), 0);
|
|
50
|
+
const shippingAmount = refund.refund_shipping_lines.reduce((sum, line) => sum + minor(line.subtotal_amount_set.shop_money.amount), 0);
|
|
51
|
+
return { ...(amount === undefined ? {} : { amount }), ...(shippingAmount > 0 ? { shippingAmount } : {}) };
|
|
52
|
+
}
|
|
30
53
|
const fulfilledPayload = z.object({
|
|
31
54
|
id,
|
|
32
55
|
fulfillments: z.array(z.object({
|
|
@@ -111,6 +134,7 @@ export async function decodeShopifyWebhook(shop: ShopifyGraphqlTarget | undefine
|
|
|
111
134
|
const externalVariantId = entry.line_item.variant_id ?? entry.line_item.product_id;
|
|
112
135
|
return externalVariantId == null ? [] : [{ externalVariantId, quantity: entry.quantity }];
|
|
113
136
|
}),
|
|
137
|
+
...refundMoney(parsed.data),
|
|
114
138
|
}]);
|
|
115
139
|
}
|
|
116
140
|
const returnStatus = RETURN_STATUS[topic];
|