@porulle/plugin-channel-connector 0.62.0 → 0.64.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.d.ts +3 -0
- package/dist/service.js +26 -3
- package/package.json +2 -2
- package/src/service.ts +32 -3
package/dist/service.d.ts
CHANGED
|
@@ -539,6 +539,9 @@ export declare class ChannelConnectorService {
|
|
|
539
539
|
private redactShopData;
|
|
540
540
|
private resolveOrderId;
|
|
541
541
|
private setMappedInventory;
|
|
542
|
+
private setInventoryLevel;
|
|
543
|
+
/** This store's mapped variant whose import recorded `metadata.inventoryItemId`; null when none, or when two claim it. */
|
|
544
|
+
private variantForInventoryItem;
|
|
542
545
|
private convergeCatalogItem;
|
|
543
546
|
private createRefundRequest;
|
|
544
547
|
private executeRefund;
|
package/dist/service.js
CHANGED
|
@@ -3737,9 +3737,20 @@ export class ChannelConnectorService {
|
|
|
3737
3737
|
}
|
|
3738
3738
|
}
|
|
3739
3739
|
else if (event.type === "inventory_levels/update") {
|
|
3740
|
-
const externalId = String(data.inventory_item_id ?? data.variation_id ?? data.product_id ?? "");
|
|
3741
3740
|
const available = Number(data.available ?? data.stock_quantity ?? 0);
|
|
3742
|
-
|
|
3741
|
+
// Shopify names an INVENTORY ITEM, whose id is not the variant id the channel map is keyed by;
|
|
3742
|
+
// looked up by it, every Shopify stock webhook found no mapping and was dropped. The variant is
|
|
3743
|
+
// resolved through the inventory item id its import recorded; a provider that sends a variant
|
|
3744
|
+
// id keeps the plain lookup.
|
|
3745
|
+
const inventoryItemId = data.inventory_item_id !== undefined && data.inventory_item_id !== null ? String(data.inventory_item_id) : null;
|
|
3746
|
+
const byInventoryItem = inventoryItemId === null ? null : await this.variantForInventoryItem(orgId, storeId, inventoryItemId);
|
|
3747
|
+
if (byInventoryItem !== null) {
|
|
3748
|
+
await this.setInventoryLevel(byInventoryItem.entityId, byInventoryItem.variantId, available, actor);
|
|
3749
|
+
}
|
|
3750
|
+
else {
|
|
3751
|
+
const externalId = String(data.variation_id ?? data.product_id ?? inventoryItemId ?? "");
|
|
3752
|
+
await this.setMappedInventory(orgId, storeId, externalId, available, actor);
|
|
3753
|
+
}
|
|
3743
3754
|
}
|
|
3744
3755
|
else if (event.type === "orders/fulfilled" || event.type === "orders/cancelled") {
|
|
3745
3756
|
const orderId = await this.resolveOrderId(orgId, storeId, data);
|
|
@@ -3849,8 +3860,20 @@ export class ChannelConnectorService {
|
|
|
3849
3860
|
const [mapping] = await this.db.select().from(channelEntityMap).where(and(eq(channelEntityMap.organizationId, orgId), eq(channelEntityMap.storeId, storeId), eq(channelEntityMap.externalId, externalId)));
|
|
3850
3861
|
if (!mapping)
|
|
3851
3862
|
return;
|
|
3863
|
+
await this.setInventoryLevel(mapping.entityId, mapping.variantId, quantity, actor);
|
|
3864
|
+
}
|
|
3865
|
+
async setInventoryLevel(entityId, variantId, quantity, actor) {
|
|
3852
3866
|
const inventory = this.services.inventory;
|
|
3853
|
-
await inventory.setAbsolute({ entityId
|
|
3867
|
+
await inventory.setAbsolute({ entityId, ...(variantId ? { variantId } : {}), quantity: Math.max(0, Math.floor(quantity)), reason: "Inventory webhook sync" }, actor);
|
|
3868
|
+
}
|
|
3869
|
+
/** This store's mapped variant whose import recorded `metadata.inventoryItemId`; null when none, or when two claim it. */
|
|
3870
|
+
async variantForInventoryItem(orgId, storeId, inventoryItemId) {
|
|
3871
|
+
const rows = await this.db.select({ entityId: channelEntityMap.entityId, variantId: channelEntityMap.variantId }).from(channelEntityMap)
|
|
3872
|
+
.innerJoin(variants, eq(variants.id, channelEntityMap.variantId))
|
|
3873
|
+
.where(and(eq(channelEntityMap.organizationId, orgId), eq(channelEntityMap.storeId, storeId), eq(channelEntityMap.kind, "variant"), sql `${variants.metadata}->>'inventoryItemId' = ${inventoryItemId}`))
|
|
3874
|
+
.limit(2);
|
|
3875
|
+
const [only] = rows;
|
|
3876
|
+
return rows.length === 1 && only !== undefined && only.variantId !== null ? { entityId: only.entityId, variantId: only.variantId } : null;
|
|
3854
3877
|
}
|
|
3855
3878
|
async convergeCatalogItem(orgId, storeId, entityId, data, actor) {
|
|
3856
3879
|
const product = data.product && typeof data.product === "object" ? data.product : data;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@porulle/plugin-channel-connector",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.64.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@hono/zod-openapi": "^1.2.2",
|
|
21
21
|
"hono": "^4.12.5",
|
|
22
|
-
"@porulle/core": "0.
|
|
22
|
+
"@porulle/core": "0.64.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^24.5.2",
|
package/src/service.ts
CHANGED
|
@@ -4798,9 +4798,19 @@ export class ChannelConnectorService {
|
|
|
4798
4798
|
}
|
|
4799
4799
|
}
|
|
4800
4800
|
} else if (event.type === "inventory_levels/update") {
|
|
4801
|
-
const externalId = String(data.inventory_item_id ?? data.variation_id ?? data.product_id ?? "");
|
|
4802
4801
|
const available = Number(data.available ?? data.stock_quantity ?? 0);
|
|
4803
|
-
|
|
4802
|
+
// Shopify names an INVENTORY ITEM, whose id is not the variant id the channel map is keyed by;
|
|
4803
|
+
// looked up by it, every Shopify stock webhook found no mapping and was dropped. The variant is
|
|
4804
|
+
// resolved through the inventory item id its import recorded; a provider that sends a variant
|
|
4805
|
+
// id keeps the plain lookup.
|
|
4806
|
+
const inventoryItemId = data.inventory_item_id !== undefined && data.inventory_item_id !== null ? String(data.inventory_item_id) : null;
|
|
4807
|
+
const byInventoryItem = inventoryItemId === null ? null : await this.variantForInventoryItem(orgId, storeId, inventoryItemId);
|
|
4808
|
+
if (byInventoryItem !== null) {
|
|
4809
|
+
await this.setInventoryLevel(byInventoryItem.entityId, byInventoryItem.variantId, available, actor);
|
|
4810
|
+
} else {
|
|
4811
|
+
const externalId = String(data.variation_id ?? data.product_id ?? inventoryItemId ?? "");
|
|
4812
|
+
await this.setMappedInventory(orgId, storeId, externalId, available, actor);
|
|
4813
|
+
}
|
|
4804
4814
|
} else if (event.type === "orders/fulfilled" || event.type === "orders/cancelled") {
|
|
4805
4815
|
const orderId = await this.resolveOrderId(orgId, storeId, data);
|
|
4806
4816
|
if (orderId) {
|
|
@@ -4913,8 +4923,27 @@ export class ChannelConnectorService {
|
|
|
4913
4923
|
private async setMappedInventory(orgId: string, storeId: string, externalId: string, quantity: number, actor: Actor): Promise<void> {
|
|
4914
4924
|
const [mapping] = await this.db.select().from(channelEntityMap).where(and(eq(channelEntityMap.organizationId, orgId), eq(channelEntityMap.storeId, storeId), eq(channelEntityMap.externalId, externalId)));
|
|
4915
4925
|
if (!mapping) return;
|
|
4926
|
+
await this.setInventoryLevel(mapping.entityId, mapping.variantId, quantity, actor);
|
|
4927
|
+
}
|
|
4928
|
+
|
|
4929
|
+
private async setInventoryLevel(entityId: string, variantId: string | null, quantity: number, actor: Actor): Promise<void> {
|
|
4916
4930
|
const inventory = this.services.inventory as { setAbsolute(input: { entityId: string; variantId?: string; quantity: number; reason?: string }, actor: Actor): Promise<{ ok: boolean }> };
|
|
4917
|
-
await inventory.setAbsolute({ entityId
|
|
4931
|
+
await inventory.setAbsolute({ entityId, ...(variantId ? { variantId } : {}), quantity: Math.max(0, Math.floor(quantity)), reason: "Inventory webhook sync" }, actor);
|
|
4932
|
+
}
|
|
4933
|
+
|
|
4934
|
+
/** This store's mapped variant whose import recorded `metadata.inventoryItemId`; null when none, or when two claim it. */
|
|
4935
|
+
private async variantForInventoryItem(orgId: string, storeId: string, inventoryItemId: string): Promise<{ entityId: string; variantId: string } | null> {
|
|
4936
|
+
const rows = await this.db.select({ entityId: channelEntityMap.entityId, variantId: channelEntityMap.variantId }).from(channelEntityMap)
|
|
4937
|
+
.innerJoin(variants, eq(variants.id, channelEntityMap.variantId))
|
|
4938
|
+
.where(and(
|
|
4939
|
+
eq(channelEntityMap.organizationId, orgId),
|
|
4940
|
+
eq(channelEntityMap.storeId, storeId),
|
|
4941
|
+
eq(channelEntityMap.kind, "variant"),
|
|
4942
|
+
sql`${variants.metadata}->>'inventoryItemId' = ${inventoryItemId}`,
|
|
4943
|
+
))
|
|
4944
|
+
.limit(2);
|
|
4945
|
+
const [only] = rows;
|
|
4946
|
+
return rows.length === 1 && only !== undefined && only.variantId !== null ? { entityId: only.entityId, variantId: only.variantId } : null;
|
|
4918
4947
|
}
|
|
4919
4948
|
|
|
4920
4949
|
private async convergeCatalogItem(
|