@fayz-ai/shop 0.18.0 → 0.21.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/{chunk-26YK5V6P.js → chunk-AKUDWFGY.js} +101 -53
- package/dist/chunk-AKUDWFGY.js.map +1 -0
- package/dist/data/provider.d.ts +32 -1
- package/dist/data/provider.d.ts.map +1 -1
- package/dist/data/supabase-provider.d.ts +17 -1
- package/dist/data/supabase-provider.d.ts.map +1 -1
- package/dist/data/tables.d.ts +6 -5
- package/dist/data/tables.d.ts.map +1 -1
- package/dist/index.js +135 -13
- package/dist/index.js.map +1 -1
- package/dist/inventory/postgrest-double.d.ts +9 -0
- package/dist/inventory/postgrest-double.d.ts.map +1 -1
- package/dist/inventory/stock-contract.d.ts +20 -1
- package/dist/inventory/stock-contract.d.ts.map +1 -1
- package/dist/inventory/supabase-stock-store.d.ts.map +1 -1
- package/dist/inventory.js +1 -1
- package/dist/providers/checkout.d.ts +1 -1
- package/dist/providers/checkout.d.ts.map +1 -1
- package/dist/providers.js.map +1 -1
- package/dist/shipping/label-provider.d.ts +1 -1
- package/dist/shipping/label-provider.d.ts.map +1 -1
- package/dist/types.d.ts +105 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/dist/chunk-26YK5V6P.js.map +0 -1
|
@@ -589,7 +589,11 @@ var T = {
|
|
|
589
589
|
productOptions: "plg_shop_product_options",
|
|
590
590
|
productVariants: "plg_shop_product_variants",
|
|
591
591
|
categories: "plg_shop_categories",
|
|
592
|
-
orders
|
|
592
|
+
// The sale is a Venda (public.orders, kind='sale', channel='shop') since
|
|
593
|
+
// 0105; v_shop_orders is it, joined to its extension and its buyer, in the
|
|
594
|
+
// shop's own vocabulary. Writes go through the RPCs.
|
|
595
|
+
orders: "v_shop_orders",
|
|
596
|
+
orderExtensions: "plg_shop_order_extensions",
|
|
593
597
|
/** 0059. Read-only here: a session pointing at an order is what marks that
|
|
594
598
|
* order as born on the storefront rather than typed into the console. */
|
|
595
599
|
checkoutSessions: "plg_shop_checkout_sessions",
|
|
@@ -620,9 +624,18 @@ var T = {
|
|
|
620
624
|
stockReasonCodes: "plg_shop_stock_reason_codes",
|
|
621
625
|
stockLocations: "plg_shop_stock_locations",
|
|
622
626
|
stockLots: "plg_shop_stock_lots",
|
|
623
|
-
|
|
627
|
+
// A stock movement is NOT a shop concept (ADR 0024). It is the inventory
|
|
628
|
+
// plugin's ledger, and the shop writes into it through the column translation
|
|
629
|
+
// in inventory/supabase-stock-store.ts. `plg_shop_stock_movements` is left
|
|
630
|
+
// behind holding the rows written before the move; it takes no new ones.
|
|
631
|
+
stockMovements: "plg_inventory_stock_movements",
|
|
624
632
|
stockReservations: "plg_shop_stock_reservations",
|
|
625
|
-
|
|
633
|
+
// The archetype's book, maintained by stock_apply from BOTH ledgers. It has
|
|
634
|
+
// to move with the movements: `plg_shop_stock_balances` was kept up to date
|
|
635
|
+
// by a trigger on the shop's movements table, so the moment writes left that
|
|
636
|
+
// table its balances would have frozen at whatever they last read — the worst
|
|
637
|
+
// failure shape, since a stale number looks exactly like a correct one.
|
|
638
|
+
stockBalances: "stock_balances",
|
|
626
639
|
// Allocation and the reservation lifecycle (0038). The strategies and TTLs are
|
|
627
640
|
// VOCABULARY — rows, not enums (I9) — so an agency widens either with an
|
|
628
641
|
// INSERT. stockLevels is a VIEW: our (variant, lot, location) balances
|
|
@@ -637,13 +650,14 @@ var T = {
|
|
|
637
650
|
// Tenant-level shop settings (0029). stock_ownership = 'external' means an
|
|
638
651
|
// ERP owns the numbers and our ledger is not authoritative for that store.
|
|
639
652
|
settings: "plg_shop_settings",
|
|
640
|
-
//
|
|
641
|
-
//
|
|
642
|
-
//
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
//
|
|
646
|
-
|
|
653
|
+
// plg_shop_*, and 0021's reasoning no longer applies: spine 148 and shop
|
|
654
|
+
// 0087 moved both names under the prefix, because the prefix is the
|
|
655
|
+
// OWNERSHIP boundary (ADR 0011) and these rows are the shop's. The
|
|
656
|
+
// unprefixed names survive only as compat views 141 left behind.
|
|
657
|
+
shippingZones: "plg_shop_shipping_zones",
|
|
658
|
+
// The store-wide delivery fallback (0015), moved by the same migration for
|
|
659
|
+
// the same reason.
|
|
660
|
+
shippingSettings: "plg_shop_shipping_settings",
|
|
647
661
|
shippingProfiles: "plg_shop_shipping_profiles",
|
|
648
662
|
// plg_*, unlike the two above: which boxes a store keeps on the shelf is a
|
|
649
663
|
// fact about running this shop, not about the business. Nothing outside the
|
|
@@ -730,18 +744,19 @@ function rowToMovement(row) {
|
|
|
730
744
|
tenantId: row.tenant_id,
|
|
731
745
|
variantId: row.variant_id ?? null,
|
|
732
746
|
productId: row.product_id ?? null,
|
|
733
|
-
|
|
747
|
+
// Reading back through the same translation as the write.
|
|
748
|
+
locationId: row.source_location_id ?? row.location_id,
|
|
734
749
|
lotId: row.lot_id ?? null,
|
|
735
|
-
kind: row.kind,
|
|
736
|
-
reasonCode: row.reason_code ?? null,
|
|
750
|
+
kind: row.movement_type ?? row.kind,
|
|
751
|
+
reasonCode: row.reason ?? row.reason_code ?? null,
|
|
737
752
|
quantity: Number(row.quantity),
|
|
738
753
|
unitCost: row.unit_cost == null ? null : Number(row.unit_cost),
|
|
739
|
-
orderId: row.order_id ?? null,
|
|
754
|
+
orderId: row.source_item_type === "order" ? row.source_item_id ?? null : row.order_id ?? null,
|
|
740
755
|
reservationId: row.reservation_id ?? null,
|
|
741
756
|
idempotencyKey: row.idempotency_key ?? null,
|
|
742
|
-
occurredAt: row.occurred_at,
|
|
743
|
-
createdBy: row.created_by ?? null,
|
|
744
|
-
note: row.note ?? null,
|
|
757
|
+
occurredAt: row.movement_date ?? row.occurred_at,
|
|
758
|
+
createdBy: row.user_id ?? row.created_by ?? null,
|
|
759
|
+
note: row.notes ?? row.note ?? null,
|
|
745
760
|
createdAt: row.created_at
|
|
746
761
|
};
|
|
747
762
|
}
|
|
@@ -752,7 +767,11 @@ function rowToBalance(row) {
|
|
|
752
767
|
id: row.id,
|
|
753
768
|
tenantId: row.tenant_id,
|
|
754
769
|
variantId: row.variant_id,
|
|
755
|
-
|
|
770
|
+
// The archetype's book is keyed on (tenant, variant, unit). It carries no
|
|
771
|
+
// lot, and `unit_id` is the BRANCH rather than a shelf — so a balance read
|
|
772
|
+
// here answers "how many in total", and WHERE they sit stays a question for
|
|
773
|
+
// the inventory positions.
|
|
774
|
+
locationId: row.unit_id ?? row.location_id ?? null,
|
|
756
775
|
lotId: row.lot_id ?? null,
|
|
757
776
|
onHand,
|
|
758
777
|
reserved,
|
|
@@ -837,23 +856,20 @@ var SupabaseStockStore = class {
|
|
|
837
856
|
if (tenantId) q = q.eq("tenant_id", tenantId);
|
|
838
857
|
if (options.variantId) q = q.eq("variant_id", options.variantId);
|
|
839
858
|
if (options.variantIds) q = q.in("variant_id", options.variantIds);
|
|
840
|
-
if (options.locationId
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
if (sellable.size === 0) return [];
|
|
845
|
-
q = q.in("location_id", [...sellable]);
|
|
859
|
+
if (options.locationId || options.lotId || options.sellableOnly) {
|
|
860
|
+
throw new Error(
|
|
861
|
+
"listBalances: the shared stock book is keyed on (tenant, variant) only. Ask plg_inventory_stock_positions for per-location or per-lot detail."
|
|
862
|
+
);
|
|
846
863
|
}
|
|
847
864
|
const { data, error } = await q;
|
|
848
865
|
if (error) throw error;
|
|
849
866
|
return (data ?? []).map(rowToBalance);
|
|
850
867
|
}
|
|
851
868
|
async getAvailable(variantId) {
|
|
852
|
-
const
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
return mirroredInventoryCount(balances, sellable);
|
|
869
|
+
const balances = await this.listBalances({ variantId });
|
|
870
|
+
let total = 0;
|
|
871
|
+
for (const balance of balances) total += Math.max(balance.onHand - balance.reserved, 0);
|
|
872
|
+
return Math.max(total, 0);
|
|
857
873
|
}
|
|
858
874
|
async listLots(options = {}) {
|
|
859
875
|
const db = getDb();
|
|
@@ -877,12 +893,18 @@ var SupabaseStockStore = class {
|
|
|
877
893
|
const tenantId = this.tenantId();
|
|
878
894
|
if (tenantId) q = q.eq("tenant_id", tenantId);
|
|
879
895
|
if (options.variantId) q = q.eq("variant_id", options.variantId);
|
|
880
|
-
if (options.lotId)
|
|
881
|
-
|
|
896
|
+
if (options.lotId) {
|
|
897
|
+
const lot = await this.readLot(options.lotId);
|
|
898
|
+
if (!lot?.serial) return [];
|
|
899
|
+
q = q.eq("batch_number", lot.serial);
|
|
900
|
+
}
|
|
901
|
+
if (options.orderId) {
|
|
902
|
+
q = q.eq("source_item_type", "order").eq("source_item_id", options.orderId);
|
|
903
|
+
}
|
|
882
904
|
if (options.kind) q = q.eq("kind", options.kind);
|
|
883
|
-
if (options.reasonCode) q = q.eq("
|
|
905
|
+
if (options.reasonCode) q = q.eq("reason", options.reasonCode);
|
|
884
906
|
const ascending = options.newestFirst === false;
|
|
885
|
-
q = q.order("
|
|
907
|
+
q = q.order("movement_date", { ascending }).order("created_at", { ascending });
|
|
886
908
|
if (options.limit != null) q = q.limit(options.limit);
|
|
887
909
|
const { data, error } = await q;
|
|
888
910
|
if (error) throw error;
|
|
@@ -959,26 +981,44 @@ var SupabaseStockStore = class {
|
|
|
959
981
|
);
|
|
960
982
|
}
|
|
961
983
|
} else {
|
|
962
|
-
|
|
984
|
+
const { data, error: error2 } = await db.rpc("shop_default_inventory_location", {
|
|
985
|
+
p_tenant_id: tenantId
|
|
986
|
+
});
|
|
987
|
+
if (error2) throw new StockMovementError(error2.message, input);
|
|
988
|
+
locationId = data ?? null;
|
|
989
|
+
}
|
|
990
|
+
if (!locationId) {
|
|
991
|
+
throw new StockMovementError(
|
|
992
|
+
`stock movement: store ${tenantId} has no default stock location to record this against`,
|
|
993
|
+
input
|
|
994
|
+
);
|
|
963
995
|
}
|
|
964
|
-
const
|
|
965
|
-
|
|
996
|
+
const line = {
|
|
997
|
+
product_id: variant.productId,
|
|
966
998
|
variant_id: input.variantId,
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
quantity: input.quantity,
|
|
972
|
-
unit_cost: input.unitCost ?? null,
|
|
973
|
-
order_id: input.orderId ?? null,
|
|
974
|
-
reservation_id: input.reservationId ?? null,
|
|
975
|
-
idempotency_key: input.idempotencyKey ?? null,
|
|
976
|
-
...input.occurredAt !== void 0 ? { occurred_at: input.occurredAt } : {},
|
|
977
|
-
note: input.note ?? null
|
|
978
|
-
// product_id is denormalised by the validator trigger from the variant,
|
|
979
|
-
// so the ledger row still names its product after an ON DELETE SET NULL.
|
|
999
|
+
quantity: input.kind === "receipt" ? Math.abs(input.quantity) : input.quantity,
|
|
1000
|
+
...input.unitCost != null ? { unit_cost: input.unitCost } : {},
|
|
1001
|
+
...lot?.serial ? { batch_number: lot.serial } : {},
|
|
1002
|
+
...input.note ? { notes: input.note } : {}
|
|
980
1003
|
};
|
|
981
|
-
const { data, error } = await db.
|
|
1004
|
+
const { data: opResult, error } = input.kind === "receipt" ? await db.rpc("inventory_receive", {
|
|
1005
|
+
p_location: locationId,
|
|
1006
|
+
p_lines: [line],
|
|
1007
|
+
p_document: {
|
|
1008
|
+
type: "shop",
|
|
1009
|
+
...input.orderId ? { ref: input.orderId } : {},
|
|
1010
|
+
...input.occurredAt ? { date: input.occurredAt.slice(0, 10) } : {}
|
|
1011
|
+
},
|
|
1012
|
+
p_idempotency_key: input.idempotencyKey ?? null
|
|
1013
|
+
}) : await db.rpc("inventory_adjust", {
|
|
1014
|
+
p_location: locationId,
|
|
1015
|
+
p_lines: [line],
|
|
1016
|
+
// The ledger requires a reason for an adjustment, and the shop's reason
|
|
1017
|
+
// code is one. Falling back to the verb keeps the movement legible
|
|
1018
|
+
// rather than refusing it over a blank field.
|
|
1019
|
+
p_reason: input.reasonCode ?? input.kind,
|
|
1020
|
+
p_idempotency_key: input.idempotencyKey ?? null
|
|
1021
|
+
});
|
|
982
1022
|
if (error) {
|
|
983
1023
|
if (error.code === UNIQUE_VIOLATION && input.idempotencyKey) {
|
|
984
1024
|
const winner = await this.findByIdempotencyKey(input.idempotencyKey);
|
|
@@ -986,7 +1026,15 @@ var SupabaseStockStore = class {
|
|
|
986
1026
|
}
|
|
987
1027
|
throw new StockMovementError(error.message ?? String(error), input);
|
|
988
1028
|
}
|
|
989
|
-
|
|
1029
|
+
const movements = opResult?.movements ?? [];
|
|
1030
|
+
const written = movements[0];
|
|
1031
|
+
if (!written) {
|
|
1032
|
+
throw new StockMovementError(
|
|
1033
|
+
"stock movement: the inventory ledger accepted the operation but returned no movement",
|
|
1034
|
+
input
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
1037
|
+
return rowToMovement(written);
|
|
990
1038
|
}
|
|
991
1039
|
// --- allocation and the reservation lifecycle (§9 step 4) ---------------------
|
|
992
1040
|
//
|
|
@@ -1463,5 +1511,5 @@ function createMockStockStore(seed = {}) {
|
|
|
1463
1511
|
}
|
|
1464
1512
|
|
|
1465
1513
|
export { BEYOND_SHOPIFY, CORE_RESERVATION_TTL_MINUTES, CORE_STOCK_ALLOCATION_STRATEGIES, CORE_STOCK_MOVEMENT_KINDS, CORE_STOCK_REASON_CODES, DEFAULT_STOCK_TRACKING, LEGACY_WRITE_REASON, MockStockStore, OPENING_BALANCE_REASON, OWN_FULFILLMENT, SHOPIFY_ADJUSTMENT_REASONS, SHOPIFY_DEFAULT_OPTION_NAME, SHOPIFY_DEFAULT_VARIANT_TITLE, SHOPIFY_QUANTITY_STATES, STOCK_LOCATION_KINDS, STOCK_LOT_STATUSES, STOCK_MOVEMENT_DIRECTIONS, STOCK_RESERVATION_STATUSES, STOCK_TRACKING_MODES, StockAllocationError, StockMovementError, SupabaseStockStore, T, TRACKING_MODES_BEYOND_SHOPIFY, V, allocateStock, clearStockAllocationStrategies, clearStockStores, clearStockVocabulary, compareStockAllocationCandidates, createMockStockStore, createSupabaseStockStore, getRegisteredStockStore, listStockAllocationStrategies, listStockAllocationStrategyKeys, listStockMovementKindKeys, listStockMovementKinds, listStockReasonCodeKeys, listStockReasonCodes, mirroredInventoryCount, registerCoreStockAllocationStrategies, registerCoreStockVocabulary, registerStockAllocationStrategy, registerStockMovementKind, registerStockReasonCode, registerStockStore, replayStockLedger, resolveAllocationStrategyKey, resolveReservationTtlMinutes, resolveStockAllocationStrategy, resolveStockMovementKind, resolveStockReasonCode, resolveStockStore, rowToStockLocation, shopifyDefaultOptions, shopifyReasonToStockReason, stockAllocationStrategyRegistry, stockBalanceKey, stockMovementKindRegistry, stockReasonCodeRegistry, toShopifyVariantTitle, validateStockMovement };
|
|
1466
|
-
//# sourceMappingURL=chunk-
|
|
1467
|
-
//# sourceMappingURL=chunk-
|
|
1514
|
+
//# sourceMappingURL=chunk-AKUDWFGY.js.map
|
|
1515
|
+
//# sourceMappingURL=chunk-AKUDWFGY.js.map
|