@rovela-ai/sdk 0.19.8 → 0.20.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/admin/api/index.d.ts +2 -2
- package/dist/admin/api/index.d.ts.map +1 -1
- package/dist/admin/api/index.js +2 -2
- package/dist/admin/api/index.js.map +1 -1
- package/dist/admin/api/orders.d.ts +49 -0
- package/dist/admin/api/orders.d.ts.map +1 -1
- package/dist/admin/api/orders.js +293 -30
- package/dist/admin/api/orders.js.map +1 -1
- package/dist/admin/api/settings.d.ts.map +1 -1
- package/dist/admin/api/settings.js +6 -1
- package/dist/admin/api/settings.js.map +1 -1
- package/dist/admin/api/shipping.d.ts +49 -0
- package/dist/admin/api/shipping.d.ts.map +1 -1
- package/dist/admin/api/shipping.js +144 -0
- package/dist/admin/api/shipping.js.map +1 -1
- package/dist/admin/components/OrderDetails.d.ts.map +1 -1
- package/dist/admin/components/OrderDetails.js +69 -1
- package/dist/admin/components/OrderDetails.js.map +1 -1
- package/dist/admin/components/ShippingSettings.d.ts.map +1 -1
- package/dist/admin/components/ShippingSettings.js +313 -134
- package/dist/admin/components/ShippingSettings.js.map +1 -1
- package/dist/admin/types.d.ts +13 -0
- package/dist/admin/types.d.ts.map +1 -1
- package/dist/checkout/api/colissimo-relays.d.ts +24 -0
- package/dist/checkout/api/colissimo-relays.d.ts.map +1 -0
- package/dist/checkout/api/colissimo-relays.js +60 -0
- package/dist/checkout/api/colissimo-relays.js.map +1 -0
- package/dist/checkout/api/manual.d.ts.map +1 -1
- package/dist/checkout/api/manual.js +21 -5
- package/dist/checkout/api/manual.js.map +1 -1
- package/dist/checkout/api/shipping.d.ts.map +1 -1
- package/dist/checkout/api/shipping.js +60 -82
- package/dist/checkout/api/shipping.js.map +1 -1
- package/dist/checkout/components/CheckoutFlow.d.ts.map +1 -1
- package/dist/checkout/components/CheckoutFlow.js +142 -3
- package/dist/checkout/components/CheckoutFlow.js.map +1 -1
- package/dist/checkout/components/ShippingOptions.d.ts +8 -1
- package/dist/checkout/components/ShippingOptions.d.ts.map +1 -1
- package/dist/checkout/components/ShippingOptions.js +40 -11
- package/dist/checkout/components/ShippingOptions.js.map +1 -1
- package/dist/checkout/components/colissimo-logo.d.ts +12 -0
- package/dist/checkout/components/colissimo-logo.d.ts.map +1 -0
- package/dist/checkout/components/colissimo-logo.js +12 -0
- package/dist/checkout/components/colissimo-logo.js.map +1 -0
- package/dist/checkout/server/create-checkout-session.d.ts.map +1 -1
- package/dist/checkout/server/create-checkout-session.js +55 -13
- package/dist/checkout/server/create-checkout-session.js.map +1 -1
- package/dist/checkout/server/handle-webhook.js +7 -3
- package/dist/checkout/server/handle-webhook.js.map +1 -1
- package/dist/checkout/server/order-service.d.ts.map +1 -1
- package/dist/checkout/server/order-service.js +25 -0
- package/dist/checkout/server/order-service.js.map +1 -1
- package/dist/checkout/server/pricing.d.ts +20 -0
- package/dist/checkout/server/pricing.d.ts.map +1 -1
- package/dist/checkout/server/pricing.js +51 -5
- package/dist/checkout/server/pricing.js.map +1 -1
- package/dist/checkout/types.d.ts +57 -1
- package/dist/checkout/types.d.ts.map +1 -1
- package/dist/core/db/queries.d.ts +157 -35
- package/dist/core/db/queries.d.ts.map +1 -1
- package/dist/core/db/queries.js +223 -1
- package/dist/core/db/queries.js.map +1 -1
- package/dist/core/db/schema.d.ts +323 -5
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.js +70 -0
- package/dist/core/db/schema.js.map +1 -1
- package/dist/core/i18n/messages/en.d.ts.map +1 -1
- package/dist/core/i18n/messages/en.js +9 -0
- package/dist/core/i18n/messages/en.js.map +1 -1
- package/dist/core/i18n/messages/fr.d.ts.map +1 -1
- package/dist/core/i18n/messages/fr.js +9 -0
- package/dist/core/i18n/messages/fr.js.map +1 -1
- package/dist/shipping/colissimo.d.ts +166 -0
- package/dist/shipping/colissimo.d.ts.map +1 -0
- package/dist/shipping/colissimo.js +424 -0
- package/dist/shipping/colissimo.js.map +1 -0
- package/dist/shipping/index.d.ts +4 -1
- package/dist/shipping/index.d.ts.map +1 -1
- package/dist/shipping/index.js +3 -1
- package/dist/shipping/index.js.map +1 -1
- package/docs/changelog/epoch-07-shipping-carriers.md +125 -0
- package/package.json +6 -1
- package/templates/store-template/.claude/skills/manage-products/SKILL.md +1 -1
- package/templates/store-template/app/api/admin/orders/[id]/colissimo-defaults/route.ts +6 -0
- package/templates/store-template/app/api/admin/orders/[id]/label/route.ts +6 -0
- package/templates/store-template/app/api/admin/orders/[id]/ship-with-colissimo/route.ts +6 -0
- package/templates/store-template/app/api/admin/shipping/colissimo/route.ts +10 -0
- package/templates/store-template/app/api/checkout/colissimo-relays/route.ts +4 -0
- package/templates/store-template/package.json +1 -1
package/dist/core/db/queries.js
CHANGED
|
@@ -1003,6 +1003,87 @@ export async function updateOrderShipping(orderId, shippingData) {
|
|
|
1003
1003
|
.returning();
|
|
1004
1004
|
return order || null;
|
|
1005
1005
|
}
|
|
1006
|
+
// =============================================================================
|
|
1007
|
+
// Shipping Labels (carrier label bytes, SDK 0.20.0)
|
|
1008
|
+
// =============================================================================
|
|
1009
|
+
/**
|
|
1010
|
+
* Self-heal for the shipping_labels table (Colissimo labels are returned as
|
|
1011
|
+
* bytes exactly once — they must be persisted at purchase time). Idempotent;
|
|
1012
|
+
* cached in-process.
|
|
1013
|
+
*/
|
|
1014
|
+
let shippingLabelsSchemaEnsured = false;
|
|
1015
|
+
export async function ensureShippingLabelsSchema() {
|
|
1016
|
+
if (shippingLabelsSchemaEnsured)
|
|
1017
|
+
return;
|
|
1018
|
+
const db = getDb();
|
|
1019
|
+
try {
|
|
1020
|
+
await db.execute(sql `
|
|
1021
|
+
CREATE TABLE IF NOT EXISTS shipping_labels (
|
|
1022
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1023
|
+
order_id uuid NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
|
|
1024
|
+
carrier varchar(50) NOT NULL,
|
|
1025
|
+
format varchar(30) NOT NULL,
|
|
1026
|
+
data text NOT NULL,
|
|
1027
|
+
created_at timestamp NOT NULL DEFAULT now()
|
|
1028
|
+
)
|
|
1029
|
+
`);
|
|
1030
|
+
await db.execute(sql `CREATE INDEX IF NOT EXISTS shipping_labels_order_id_idx ON shipping_labels (order_id)`);
|
|
1031
|
+
shippingLabelsSchemaEnsured = true;
|
|
1032
|
+
}
|
|
1033
|
+
catch (err) {
|
|
1034
|
+
console.error('[ensureShippingLabelsSchema] migration failed:', err);
|
|
1035
|
+
throw err;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
/** Persist a carrier label document (base64 bytes). */
|
|
1039
|
+
export async function saveShippingLabel(params) {
|
|
1040
|
+
await ensureShippingLabelsSchema();
|
|
1041
|
+
const db = getDb();
|
|
1042
|
+
await db.insert(schema.shippingLabels).values({
|
|
1043
|
+
orderId: params.orderId,
|
|
1044
|
+
carrier: params.carrier,
|
|
1045
|
+
format: params.format,
|
|
1046
|
+
data: params.dataBase64,
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
/** Latest stored label for an order (admin-gated download route). */
|
|
1050
|
+
export async function findShippingLabelByOrderId(orderId) {
|
|
1051
|
+
await ensureShippingLabelsSchema();
|
|
1052
|
+
const db = getDb();
|
|
1053
|
+
const [label] = await db
|
|
1054
|
+
.select()
|
|
1055
|
+
.from(schema.shippingLabels)
|
|
1056
|
+
.where(eq(schema.shippingLabels.orderId, orderId))
|
|
1057
|
+
.orderBy(desc(schema.shippingLabels.createdAt))
|
|
1058
|
+
.limit(1);
|
|
1059
|
+
return label || null;
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Per-line weights for parcel-weight estimation (Colissimo). Product weight
|
|
1063
|
+
* lives in the `weight` metafield (kg — the PrestaShop-import convention);
|
|
1064
|
+
* lines whose product has no weight metafield return null so the caller can
|
|
1065
|
+
* apply the store's default item weight.
|
|
1066
|
+
*/
|
|
1067
|
+
export async function getOrderItemWeights(orderId) {
|
|
1068
|
+
const db = getDb();
|
|
1069
|
+
const rows = await db
|
|
1070
|
+
.select({
|
|
1071
|
+
quantity: schema.orderItems.quantity,
|
|
1072
|
+
metafields: schema.products.metafields,
|
|
1073
|
+
})
|
|
1074
|
+
.from(schema.orderItems)
|
|
1075
|
+
.leftJoin(schema.products, eq(schema.products.id, schema.orderItems.productId))
|
|
1076
|
+
.where(eq(schema.orderItems.orderId, orderId));
|
|
1077
|
+
return rows.map((r) => {
|
|
1078
|
+
const list = r.metafields ?? [];
|
|
1079
|
+
const raw = list.find((m) => m?.key === 'weight')?.value;
|
|
1080
|
+
const parsed = raw !== undefined ? Number.parseFloat(String(raw)) : NaN;
|
|
1081
|
+
return {
|
|
1082
|
+
quantity: r.quantity,
|
|
1083
|
+
weightKg: Number.isFinite(parsed) && parsed > 0 ? parsed : null,
|
|
1084
|
+
};
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1006
1087
|
/**
|
|
1007
1088
|
* Find order by Stripe Payment Intent ID
|
|
1008
1089
|
* Used for idempotency in webhook handling
|
|
@@ -1807,6 +1888,10 @@ export async function ensurePaymentMethodsSchema() {
|
|
|
1807
1888
|
// Email locale (i18n B3): the locale the order was placed in — drives its
|
|
1808
1889
|
// lifecycle emails. customers.locale rides ensureCustomerGroupsSchema.
|
|
1809
1890
|
await db.execute(sql `ALTER TABLE orders ADD COLUMN IF NOT EXISTS locale varchar(5)`);
|
|
1891
|
+
// Carrier relay delivery (SDK 0.20.0 — Colissimo Point Retrait): the
|
|
1892
|
+
// carrier pickup-point the customer chose. shippingAddress snapshots the
|
|
1893
|
+
// relay's address; this keeps the carrier point id/type for labels.
|
|
1894
|
+
await db.execute(sql `ALTER TABLE orders ADD COLUMN IF NOT EXISTS relay jsonb`);
|
|
1810
1895
|
// Group gating (Phase 4) — payment_methods reads all pass through here.
|
|
1811
1896
|
await ensureVisibilityColumns();
|
|
1812
1897
|
paymentMethodsSchemaEnsured = true;
|
|
@@ -2447,6 +2532,19 @@ export async function ensureStoreSettingsSchema() {
|
|
|
2447
2532
|
await db.execute(sql `
|
|
2448
2533
|
ALTER TABLE store_settings
|
|
2449
2534
|
ADD COLUMN IF NOT EXISTS public_metafield_keys jsonb NOT NULL DEFAULT '[]'::jsonb
|
|
2535
|
+
`);
|
|
2536
|
+
// Colissimo carrier integration (SDK 0.20.0). Credentials are server-only
|
|
2537
|
+
// secrets — excluded from the public settings allowlist by construction.
|
|
2538
|
+
// Relay PRICING deliberately has no settings columns: relay offers are
|
|
2539
|
+
// ordinary shipping_rates rows (fulfillment='relay') under a colissimo
|
|
2540
|
+
// carrier — one pricing engine for every carrier.
|
|
2541
|
+
await db.execute(sql `
|
|
2542
|
+
ALTER TABLE store_settings
|
|
2543
|
+
ADD COLUMN IF NOT EXISTS colissimo_contract_number varchar(20),
|
|
2544
|
+
ADD COLUMN IF NOT EXISTS colissimo_password varchar(64),
|
|
2545
|
+
ADD COLUMN IF NOT EXISTS colissimo_enabled boolean DEFAULT false,
|
|
2546
|
+
ADD COLUMN IF NOT EXISTS colissimo_sender_address jsonb,
|
|
2547
|
+
ADD COLUMN IF NOT EXISTS colissimo_default_weight_kg decimal(8,2)
|
|
2450
2548
|
`);
|
|
2451
2549
|
storeSettingsSchemaEnsured = true;
|
|
2452
2550
|
}
|
|
@@ -2642,6 +2740,14 @@ export async function findSettings() {
|
|
|
2642
2740
|
shippoTestMode: settings.shippoTestMode,
|
|
2643
2741
|
shippoFromAddress: settings.shippoFromAddress,
|
|
2644
2742
|
shippoDefaultParcel: settings.shippoDefaultParcel,
|
|
2743
|
+
// Colissimo fields (SDK 0.20.0)
|
|
2744
|
+
colissimoContractNumber: settings.colissimoContractNumber,
|
|
2745
|
+
colissimoPassword: settings.colissimoPassword,
|
|
2746
|
+
colissimoEnabled: settings.colissimoEnabled,
|
|
2747
|
+
colissimoSenderAddress: settings.colissimoSenderAddress,
|
|
2748
|
+
colissimoDefaultWeightKg: settings.colissimoDefaultWeightKg
|
|
2749
|
+
? Number(settings.colissimoDefaultWeightKg)
|
|
2750
|
+
: null,
|
|
2645
2751
|
// Discount/promotion configuration
|
|
2646
2752
|
promotionCodesEnabled: settings.promotionCodesEnabled,
|
|
2647
2753
|
// Cookie consent banner (R021)
|
|
@@ -2722,6 +2828,15 @@ export async function upsertSettings(data) {
|
|
|
2722
2828
|
shippoTestMode: data.shippoTestMode ?? undefined,
|
|
2723
2829
|
shippoFromAddress: data.shippoFromAddress ?? undefined,
|
|
2724
2830
|
shippoDefaultParcel: data.shippoDefaultParcel ?? undefined,
|
|
2831
|
+
// Colissimo (SDK 0.20.0). Credentials map explicit null -> NULL (the
|
|
2832
|
+
// disconnect route clears them), like the branding pointers above.
|
|
2833
|
+
colissimoContractNumber: data.colissimoContractNumber !== undefined ? data.colissimoContractNumber : undefined,
|
|
2834
|
+
colissimoPassword: data.colissimoPassword !== undefined ? data.colissimoPassword : undefined,
|
|
2835
|
+
colissimoEnabled: data.colissimoEnabled ?? undefined,
|
|
2836
|
+
colissimoSenderAddress: data.colissimoSenderAddress ?? undefined,
|
|
2837
|
+
colissimoDefaultWeightKg: data.colissimoDefaultWeightKg !== null && data.colissimoDefaultWeightKg !== undefined
|
|
2838
|
+
? String(data.colissimoDefaultWeightKg)
|
|
2839
|
+
: undefined,
|
|
2725
2840
|
// Discount/promotion configuration
|
|
2726
2841
|
promotionCodesEnabled: data.promotionCodesEnabled ?? undefined,
|
|
2727
2842
|
// Cookie consent banner (R021)
|
|
@@ -2773,6 +2888,14 @@ export async function upsertSettings(data) {
|
|
|
2773
2888
|
shippoTestMode: result.shippoTestMode,
|
|
2774
2889
|
shippoFromAddress: result.shippoFromAddress,
|
|
2775
2890
|
shippoDefaultParcel: result.shippoDefaultParcel,
|
|
2891
|
+
// Colissimo fields (SDK 0.20.0)
|
|
2892
|
+
colissimoContractNumber: result.colissimoContractNumber,
|
|
2893
|
+
colissimoPassword: result.colissimoPassword,
|
|
2894
|
+
colissimoEnabled: result.colissimoEnabled,
|
|
2895
|
+
colissimoSenderAddress: result.colissimoSenderAddress,
|
|
2896
|
+
colissimoDefaultWeightKg: result.colissimoDefaultWeightKg
|
|
2897
|
+
? Number(result.colissimoDefaultWeightKg)
|
|
2898
|
+
: null,
|
|
2776
2899
|
// Discount/promotion configuration
|
|
2777
2900
|
promotionCodesEnabled: result.promotionCodesEnabled,
|
|
2778
2901
|
// Cookie consent banner (R021)
|
|
@@ -2781,10 +2904,72 @@ export async function upsertSettings(data) {
|
|
|
2781
2904
|
publicMetafieldKeys: result.publicMetafieldKeys ?? [],
|
|
2782
2905
|
};
|
|
2783
2906
|
}
|
|
2907
|
+
/**
|
|
2908
|
+
* Self-heal for the carrier-registry columns (SDK 0.20.0):
|
|
2909
|
+
* shipping_carriers.provider/logo_url + shipping_rates.fulfillment. Drizzle
|
|
2910
|
+
* `select()` enumerates every declared column, so every carrier/rate read
|
|
2911
|
+
* chokepoint calls this first. Idempotent; cached in-process.
|
|
2912
|
+
*/
|
|
2913
|
+
let shippingCarrierSchemaEnsured = false;
|
|
2914
|
+
export async function ensureShippingCarrierSchema() {
|
|
2915
|
+
if (shippingCarrierSchemaEnsured)
|
|
2916
|
+
return;
|
|
2917
|
+
const db = getDb();
|
|
2918
|
+
try {
|
|
2919
|
+
await db.execute(sql `
|
|
2920
|
+
ALTER TABLE shipping_carriers
|
|
2921
|
+
ADD COLUMN IF NOT EXISTS provider varchar(20) NOT NULL DEFAULT 'manual',
|
|
2922
|
+
ADD COLUMN IF NOT EXISTS logo_url varchar(500)
|
|
2923
|
+
`);
|
|
2924
|
+
await db.execute(sql `
|
|
2925
|
+
ALTER TABLE shipping_rates
|
|
2926
|
+
ADD COLUMN IF NOT EXISTS fulfillment varchar(20) NOT NULL DEFAULT 'home'
|
|
2927
|
+
`);
|
|
2928
|
+
shippingCarrierSchemaEnsured = true;
|
|
2929
|
+
}
|
|
2930
|
+
catch (err) {
|
|
2931
|
+
console.error('[ensureShippingCarrierSchema] migration failed:', err);
|
|
2932
|
+
throw err;
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
/** Best-effort variant — never throws (the subsequent read surfaces real errors). */
|
|
2936
|
+
export async function ensureShippingCarrierSchemaSafe() {
|
|
2937
|
+
try {
|
|
2938
|
+
await ensureShippingCarrierSchema();
|
|
2939
|
+
}
|
|
2940
|
+
catch {
|
|
2941
|
+
// Swallow — the caller's own query reports the real failure.
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
/**
|
|
2945
|
+
* Legacy-mode self-heal: a store that ran `shipping_mode = 'shippo'` (the
|
|
2946
|
+
* retired global either/or) gets a shippo carrier ROW in the registry so its
|
|
2947
|
+
* live quotes keep flowing under the multi-carrier model. Idempotent
|
|
2948
|
+
* (INSERT … WHERE NOT EXISTS); cached in-process.
|
|
2949
|
+
*/
|
|
2950
|
+
let legacyShippoCarrierEnsured = false;
|
|
2951
|
+
export async function ensureLegacyShippoCarrier(shippingMode) {
|
|
2952
|
+
if (legacyShippoCarrierEnsured || shippingMode !== 'shippo')
|
|
2953
|
+
return;
|
|
2954
|
+
try {
|
|
2955
|
+
await ensureShippingCarrierSchema();
|
|
2956
|
+
const db = getDb();
|
|
2957
|
+
await db.execute(sql `
|
|
2958
|
+
INSERT INTO shipping_carriers (name, code, provider, is_active, sort_order)
|
|
2959
|
+
SELECT 'Carrier rates', 'shippo', 'shippo', true, 0
|
|
2960
|
+
WHERE NOT EXISTS (SELECT 1 FROM shipping_carriers WHERE provider = 'shippo')
|
|
2961
|
+
`);
|
|
2962
|
+
legacyShippoCarrierEnsured = true;
|
|
2963
|
+
}
|
|
2964
|
+
catch (err) {
|
|
2965
|
+
console.error('[ensureLegacyShippoCarrier] failed (non-fatal):', err);
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2784
2968
|
/**
|
|
2785
2969
|
* Find all shipping carriers
|
|
2786
2970
|
*/
|
|
2787
2971
|
export async function findShippingCarriers() {
|
|
2972
|
+
await ensureShippingCarrierSchemaSafe();
|
|
2788
2973
|
const db = getDb();
|
|
2789
2974
|
const carriers = await db
|
|
2790
2975
|
.select()
|
|
@@ -2795,6 +2980,8 @@ export async function findShippingCarriers() {
|
|
|
2795
2980
|
name: carrier.name,
|
|
2796
2981
|
code: carrier.code,
|
|
2797
2982
|
description: carrier.description,
|
|
2983
|
+
provider: carrier.provider ?? 'manual',
|
|
2984
|
+
logoUrl: carrier.logoUrl ?? null,
|
|
2798
2985
|
isActive: carrier.isActive,
|
|
2799
2986
|
sortOrder: carrier.sortOrder,
|
|
2800
2987
|
createdAt: carrier.createdAt,
|
|
@@ -2805,6 +2992,7 @@ export async function findShippingCarriers() {
|
|
|
2805
2992
|
* Find active shipping carriers only
|
|
2806
2993
|
*/
|
|
2807
2994
|
export async function findActiveShippingCarriers() {
|
|
2995
|
+
await ensureShippingCarrierSchemaSafe();
|
|
2808
2996
|
const db = getDb();
|
|
2809
2997
|
const carriers = await db
|
|
2810
2998
|
.select()
|
|
@@ -2816,6 +3004,8 @@ export async function findActiveShippingCarriers() {
|
|
|
2816
3004
|
name: carrier.name,
|
|
2817
3005
|
code: carrier.code,
|
|
2818
3006
|
description: carrier.description,
|
|
3007
|
+
provider: carrier.provider ?? 'manual',
|
|
3008
|
+
logoUrl: carrier.logoUrl ?? null,
|
|
2819
3009
|
isActive: carrier.isActive,
|
|
2820
3010
|
sortOrder: carrier.sortOrder,
|
|
2821
3011
|
createdAt: carrier.createdAt,
|
|
@@ -2826,6 +3016,7 @@ export async function findActiveShippingCarriers() {
|
|
|
2826
3016
|
* Find a shipping carrier by ID
|
|
2827
3017
|
*/
|
|
2828
3018
|
export async function findShippingCarrierById(id) {
|
|
3019
|
+
await ensureShippingCarrierSchemaSafe();
|
|
2829
3020
|
const db = getDb();
|
|
2830
3021
|
const [carrier] = await db
|
|
2831
3022
|
.select()
|
|
@@ -2839,6 +3030,8 @@ export async function findShippingCarrierById(id) {
|
|
|
2839
3030
|
name: carrier.name,
|
|
2840
3031
|
code: carrier.code,
|
|
2841
3032
|
description: carrier.description,
|
|
3033
|
+
provider: carrier.provider ?? 'manual',
|
|
3034
|
+
logoUrl: carrier.logoUrl ?? null,
|
|
2842
3035
|
isActive: carrier.isActive,
|
|
2843
3036
|
sortOrder: carrier.sortOrder,
|
|
2844
3037
|
createdAt: carrier.createdAt,
|
|
@@ -2849,6 +3042,7 @@ export async function findShippingCarrierById(id) {
|
|
|
2849
3042
|
* Create a new shipping carrier
|
|
2850
3043
|
*/
|
|
2851
3044
|
export async function createShippingCarrier(data) {
|
|
3045
|
+
await ensureShippingCarrierSchema();
|
|
2852
3046
|
const db = getDb();
|
|
2853
3047
|
const [carrier] = await db
|
|
2854
3048
|
.insert(schema.shippingCarriers)
|
|
@@ -2856,6 +3050,8 @@ export async function createShippingCarrier(data) {
|
|
|
2856
3050
|
name: data.name,
|
|
2857
3051
|
code: data.code,
|
|
2858
3052
|
description: data.description || null,
|
|
3053
|
+
provider: data.provider || 'manual',
|
|
3054
|
+
logoUrl: data.logoUrl ?? null,
|
|
2859
3055
|
isActive: data.isActive ?? true,
|
|
2860
3056
|
sortOrder: data.sortOrder ?? 0,
|
|
2861
3057
|
})
|
|
@@ -2866,6 +3062,7 @@ export async function createShippingCarrier(data) {
|
|
|
2866
3062
|
* Update a shipping carrier
|
|
2867
3063
|
*/
|
|
2868
3064
|
export async function updateShippingCarrier(id, data) {
|
|
3065
|
+
await ensureShippingCarrierSchemaSafe();
|
|
2869
3066
|
const db = getDb();
|
|
2870
3067
|
const [carrier] = await db
|
|
2871
3068
|
.update(schema.shippingCarriers)
|
|
@@ -2909,8 +3106,10 @@ export async function findCarriersWithZonesAndRates() {
|
|
|
2909
3106
|
* Find all shipping zones with their rates and carrier info
|
|
2910
3107
|
*/
|
|
2911
3108
|
export async function findShippingZones() {
|
|
2912
|
-
// Rate SELECTs enumerate visible_to_groups — self-heal older
|
|
3109
|
+
// Rate SELECTs enumerate visible_to_groups + fulfillment — self-heal older
|
|
3110
|
+
// stores first.
|
|
2913
3111
|
await ensureVisibilityColumnsSafe();
|
|
3112
|
+
await ensureShippingCarrierSchemaSafe();
|
|
2914
3113
|
const db = getDb();
|
|
2915
3114
|
// Get all zones with carrier info via join
|
|
2916
3115
|
const zonesWithCarriers = await db
|
|
@@ -2920,6 +3119,9 @@ export async function findShippingZones() {
|
|
|
2920
3119
|
id: schema.shippingCarriers.id,
|
|
2921
3120
|
name: schema.shippingCarriers.name,
|
|
2922
3121
|
code: schema.shippingCarriers.code,
|
|
3122
|
+
provider: schema.shippingCarriers.provider,
|
|
3123
|
+
logoUrl: schema.shippingCarriers.logoUrl,
|
|
3124
|
+
isActive: schema.shippingCarriers.isActive,
|
|
2923
3125
|
},
|
|
2924
3126
|
})
|
|
2925
3127
|
.from(schema.shippingZones)
|
|
@@ -2945,6 +3147,9 @@ export async function findShippingZones() {
|
|
|
2945
3147
|
id: carrier.id,
|
|
2946
3148
|
name: carrier.name,
|
|
2947
3149
|
code: carrier.code,
|
|
3150
|
+
provider: carrier.provider ?? 'manual',
|
|
3151
|
+
logoUrl: carrier.logoUrl ?? null,
|
|
3152
|
+
isActive: carrier.isActive ?? true,
|
|
2948
3153
|
} : undefined,
|
|
2949
3154
|
name: zone.name,
|
|
2950
3155
|
countries: zone.countries || [],
|
|
@@ -2963,6 +3168,7 @@ export async function findShippingZones() {
|
|
|
2963
3168
|
isActive: rate.isActive,
|
|
2964
3169
|
sortOrder: rate.sortOrder,
|
|
2965
3170
|
visibleToGroups: Array.isArray(rate.visibleToGroups) ? rate.visibleToGroups : [],
|
|
3171
|
+
fulfillment: rate.fulfillment === 'relay' ? 'relay' : 'home',
|
|
2966
3172
|
})),
|
|
2967
3173
|
}));
|
|
2968
3174
|
}
|
|
@@ -3025,6 +3231,7 @@ export async function deleteShippingZone(id) {
|
|
|
3025
3231
|
*/
|
|
3026
3232
|
export async function createShippingRate(data) {
|
|
3027
3233
|
await ensureVisibilityColumnsSafe();
|
|
3234
|
+
await ensureShippingCarrierSchemaSafe();
|
|
3028
3235
|
const db = getDb();
|
|
3029
3236
|
const [rate] = await db
|
|
3030
3237
|
.insert(schema.shippingRates)
|
|
@@ -3039,6 +3246,7 @@ export async function createShippingRate(data) {
|
|
|
3039
3246
|
isActive: data.isActive ?? true,
|
|
3040
3247
|
sortOrder: data.sortOrder ?? 0,
|
|
3041
3248
|
visibleToGroups: data.visibleToGroups ?? [],
|
|
3249
|
+
fulfillment: data.fulfillment ?? 'home',
|
|
3042
3250
|
})
|
|
3043
3251
|
.returning();
|
|
3044
3252
|
return rate;
|
|
@@ -3048,6 +3256,7 @@ export async function createShippingRate(data) {
|
|
|
3048
3256
|
*/
|
|
3049
3257
|
export async function updateShippingRate(id, data) {
|
|
3050
3258
|
await ensureVisibilityColumnsSafe();
|
|
3259
|
+
await ensureShippingCarrierSchemaSafe();
|
|
3051
3260
|
const db = getDb();
|
|
3052
3261
|
const updateData = {};
|
|
3053
3262
|
if (data.name !== undefined)
|
|
@@ -3068,6 +3277,8 @@ export async function updateShippingRate(id, data) {
|
|
|
3068
3277
|
updateData.sortOrder = data.sortOrder;
|
|
3069
3278
|
if (data.visibleToGroups !== undefined)
|
|
3070
3279
|
updateData.visibleToGroups = data.visibleToGroups;
|
|
3280
|
+
if (data.fulfillment !== undefined)
|
|
3281
|
+
updateData.fulfillment = data.fulfillment;
|
|
3071
3282
|
const [rate] = await db
|
|
3072
3283
|
.update(schema.shippingRates)
|
|
3073
3284
|
.set(updateData)
|
|
@@ -3101,6 +3312,10 @@ export async function findShippingRatesForCountry(country, orderAmount, groupId)
|
|
|
3101
3312
|
// Skip zones without a carrier (shouldn't happen, but defensive)
|
|
3102
3313
|
if (!zone.carrier)
|
|
3103
3314
|
continue;
|
|
3315
|
+
// A deactivated CARRIER withdraws all its offers (registry semantics —
|
|
3316
|
+
// pre-0.20.0 the flag was cosmetic in the quote path).
|
|
3317
|
+
if (!zone.carrier.isActive)
|
|
3318
|
+
continue;
|
|
3104
3319
|
// Check if zone covers this country
|
|
3105
3320
|
// '*' means all countries (international catch-all)
|
|
3106
3321
|
const coversCountry = zone.countries.includes('*') || zone.countries.includes(country.toUpperCase());
|
|
@@ -3124,11 +3339,14 @@ export async function findShippingRatesForCountry(country, orderAmount, groupId)
|
|
|
3124
3339
|
carrierId: zone.carrierId,
|
|
3125
3340
|
carrierName: zone.carrier.name,
|
|
3126
3341
|
carrierCode: zone.carrier.code,
|
|
3342
|
+
carrierProvider: zone.carrier.provider,
|
|
3343
|
+
carrierLogoUrl: zone.carrier.logoUrl,
|
|
3127
3344
|
zoneName: zone.name,
|
|
3128
3345
|
name: rate.name,
|
|
3129
3346
|
description: rate.description,
|
|
3130
3347
|
price: rate.price,
|
|
3131
3348
|
estimatedDays: rate.estimatedDays,
|
|
3349
|
+
fulfillment: rate.fulfillment,
|
|
3132
3350
|
});
|
|
3133
3351
|
}
|
|
3134
3352
|
}
|
|
@@ -3154,6 +3372,8 @@ export async function findShippingOptionsForCountry(country, orderAmount, groupI
|
|
|
3154
3372
|
id: rate.carrierId,
|
|
3155
3373
|
name: rate.carrierName,
|
|
3156
3374
|
code: rate.carrierCode,
|
|
3375
|
+
provider: rate.carrierProvider,
|
|
3376
|
+
logoUrl: rate.carrierLogoUrl,
|
|
3157
3377
|
},
|
|
3158
3378
|
options: [],
|
|
3159
3379
|
};
|
|
@@ -3169,6 +3389,8 @@ export async function findShippingOptionsForCountry(country, orderAmount, groupI
|
|
|
3169
3389
|
price: rate.price,
|
|
3170
3390
|
estimatedDays: rate.estimatedDays ?? undefined,
|
|
3171
3391
|
source: 'manual',
|
|
3392
|
+
provider: rate.carrierProvider,
|
|
3393
|
+
fulfillment: rate.fulfillment,
|
|
3172
3394
|
});
|
|
3173
3395
|
}
|
|
3174
3396
|
// Convert to array and sort by carrier name
|