@porulle/plugin-channel-connector 0.70.2 → 0.72.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/dist/service.js +13 -3
- package/package.json +4 -4
- package/src/service.ts +13 -2
package/dist/service.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { CommerceInvalidTransitionError, CommerceNotFoundError, CommerceValidationError, Ok, PluginErr, createTxContext, createSystemActor, linkFieldPaths, removeEntityLinks, writeEntityLinks, } from "@porulle/core";
|
|
3
|
+
import { CHANNEL_OUT_OF_STOCK, CommerceInvalidTransitionError, CommerceNotFoundError, CommerceValidationError, Ok, PluginErr, createTxContext, createSystemActor, linkFieldPaths, removeEntityLinks, writeEntityLinks, } from "@porulle/core";
|
|
4
4
|
import { isValidFieldPath, requireUserId } from "@porulle/core";
|
|
5
5
|
import { CHANNEL_CONVERGENCE_CTX } from "./catalog-push-trigger.js";
|
|
6
6
|
import { resolveLiveCredentials, withLiveCredentials } from "./live-credentials.js";
|
|
@@ -4452,7 +4452,14 @@ export class ChannelConnectorService {
|
|
|
4452
4452
|
.where(and(eq(channelOrderExports.organizationId, orgId), eq(channelOrderExports.id, created.value.id)));
|
|
4453
4453
|
const pushed = await connector.pushOrder(store, slice);
|
|
4454
4454
|
if (!pushed.ok) {
|
|
4455
|
-
|
|
4455
|
+
const failed = await this.transitionExport(orgId, created.value.id, "failed", requireUserId(actor), pushed.error.message, pushed.error.retriable === true ? "transient" : "definitive");
|
|
4456
|
+
if (pushed.error.code === CHANNEL_OUT_OF_STOCK) {
|
|
4457
|
+
// The store has said nobody will send these goods: cancel, and let the host's cancel path
|
|
4458
|
+
// refund the shopper. Any other refusal can be fixed and retried, so it waits for an operator.
|
|
4459
|
+
const ordersService = this.services.orders;
|
|
4460
|
+
await ordersService.changeStatus({ orderId: slice.orderId, newStatus: "cancelled", reason: "channel_out_of_stock" }, actor);
|
|
4461
|
+
}
|
|
4462
|
+
return failed;
|
|
4456
4463
|
}
|
|
4457
4464
|
await this.db
|
|
4458
4465
|
.update(channelOrderExports)
|
|
@@ -4535,7 +4542,10 @@ export class ChannelConnectorService {
|
|
|
4535
4542
|
const linesTotal = lines.reduce((sum, line) => sum + line.totalPrice, 0);
|
|
4536
4543
|
// ponytail: a multi-store order sends no shipping to any store; apportion it when such orders exist.
|
|
4537
4544
|
const shipping = selected.length === lineItems.length && order.shippingTotal > 0 ? { title: "Shipping", amount: order.shippingTotal } : null;
|
|
4538
|
-
|
|
4545
|
+
// ponytail: like delivery, a discount is sent only with the whole order; apportion it when multi-store orders exist.
|
|
4546
|
+
const discountCode = typeof metadata.promotionCode === "string" && metadata.promotionCode.trim() !== "" ? metadata.promotionCode.trim() : "DISCOUNT";
|
|
4547
|
+
const discount = selected.length === lineItems.length && order.discountTotal > 0 ? { code: discountCode, amount: order.discountTotal } : null;
|
|
4548
|
+
return Ok({ orderId, currency: order.currency, grandTotal: linesTotal + (shipping?.amount ?? 0) - (discount?.amount ?? 0), lines, ...(shipping ? { shipping } : {}), ...(discount ? { discount } : {}), customer: { name, email, shippingAddress } });
|
|
4539
4549
|
}
|
|
4540
4550
|
async reapExports(input) {
|
|
4541
4551
|
const now = Date.now();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@porulle/plugin-channel-connector",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@hono/zod-openapi": "^1.2.2",
|
|
24
24
|
"hono": "^4.12.5",
|
|
25
|
-
"@porulle/core": "0.
|
|
25
|
+
"@porulle/core": "0.72.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^24.5.2",
|
|
29
29
|
"eslint": "^9.39.1",
|
|
30
30
|
"typescript": "5.9.2",
|
|
31
31
|
"vitest": "^3.2.4",
|
|
32
|
-
"@porulle/
|
|
33
|
-
"@porulle/
|
|
32
|
+
"@porulle/typescript-config": "0.1.0",
|
|
33
|
+
"@porulle/eslint-config": "0.1.0"
|
|
34
34
|
},
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
package/src/service.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import {
|
|
4
|
+
CHANNEL_OUT_OF_STOCK,
|
|
4
5
|
CommerceInvalidTransitionError,
|
|
5
6
|
CommerceNotFoundError,
|
|
6
7
|
CommerceValidationError,
|
|
@@ -5613,7 +5614,7 @@ export class ChannelConnectorService {
|
|
|
5613
5614
|
|
|
5614
5615
|
const pushed = await connector.pushOrder(store as ChannelStore, slice);
|
|
5615
5616
|
if (!pushed.ok) {
|
|
5616
|
-
|
|
5617
|
+
const failed = await this.transitionExport(
|
|
5617
5618
|
orgId,
|
|
5618
5619
|
created.value.id,
|
|
5619
5620
|
"failed",
|
|
@@ -5621,6 +5622,13 @@ export class ChannelConnectorService {
|
|
|
5621
5622
|
pushed.error.message,
|
|
5622
5623
|
pushed.error.retriable === true ? "transient" : "definitive",
|
|
5623
5624
|
);
|
|
5625
|
+
if (pushed.error.code === CHANNEL_OUT_OF_STOCK) {
|
|
5626
|
+
// The store has said nobody will send these goods: cancel, and let the host's cancel path
|
|
5627
|
+
// refund the shopper. Any other refusal can be fixed and retried, so it waits for an operator.
|
|
5628
|
+
const ordersService = this.services.orders as { changeStatus(input: { orderId: string; newStatus: "cancelled"; reason: string }, actor: Actor): Promise<{ ok: boolean }> };
|
|
5629
|
+
await ordersService.changeStatus({ orderId: slice.orderId, newStatus: "cancelled", reason: "channel_out_of_stock" }, actor);
|
|
5630
|
+
}
|
|
5631
|
+
return failed;
|
|
5624
5632
|
}
|
|
5625
5633
|
|
|
5626
5634
|
await this.db
|
|
@@ -5733,7 +5741,10 @@ export class ChannelConnectorService {
|
|
|
5733
5741
|
const linesTotal = lines.reduce((sum, line) => sum + line.totalPrice, 0);
|
|
5734
5742
|
// ponytail: a multi-store order sends no shipping to any store; apportion it when such orders exist.
|
|
5735
5743
|
const shipping = selected.length === lineItems.length && order.shippingTotal > 0 ? { title: "Shipping", amount: order.shippingTotal } : null;
|
|
5736
|
-
|
|
5744
|
+
// ponytail: like delivery, a discount is sent only with the whole order; apportion it when multi-store orders exist.
|
|
5745
|
+
const discountCode = typeof metadata.promotionCode === "string" && metadata.promotionCode.trim() !== "" ? metadata.promotionCode.trim() : "DISCOUNT";
|
|
5746
|
+
const discount = selected.length === lineItems.length && order.discountTotal > 0 ? { code: discountCode, amount: order.discountTotal } : null;
|
|
5747
|
+
return Ok({ orderId, currency: order.currency, grandTotal: linesTotal + (shipping?.amount ?? 0) - (discount?.amount ?? 0), lines, ...(shipping ? { shipping } : {}), ...(discount ? { discount } : {}), customer: { name, email, shippingAddress } });
|
|
5737
5748
|
}
|
|
5738
5749
|
|
|
5739
5750
|
async reapExports(input: { definitiveMs: number; transientMs: number }): Promise<{ abandonedCount: number; refundedOrderIds: string[] }> {
|