@flowselections/floriday-verkoop-module 1.0.12 → 1.0.14
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-lib/components/verkoop/AutoFulfillmentStatusCard.d.ts +4 -0
- package/dist-lib/components/verkoop/AutoFulfillmentStatusCard.d.ts.map +1 -0
- package/dist-lib/components/verkoop/AutoFulfillmentStatusCard.js +95 -0
- package/dist-lib/components/verkoop/CartAssignmentWizard.d.ts +6 -0
- package/dist-lib/components/verkoop/CartAssignmentWizard.d.ts.map +1 -0
- package/dist-lib/components/verkoop/CartAssignmentWizard.js +194 -0
- package/dist-lib/components/verkoop/CreateOrderPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/CreateOrderPage.js +14 -4
- package/dist-lib/components/verkoop/OrderAfleverbrievenCard.d.ts +4 -0
- package/dist-lib/components/verkoop/OrderAfleverbrievenCard.d.ts.map +1 -0
- package/dist-lib/components/verkoop/OrderAfleverbrievenCard.js +44 -0
- package/dist-lib/components/verkoop/OrderKarindelingCard.d.ts +5 -0
- package/dist-lib/components/verkoop/OrderKarindelingCard.d.ts.map +1 -0
- package/dist-lib/components/verkoop/OrderKarindelingCard.js +160 -0
- package/dist-lib/components/verkoop/SalesOrderDetailView.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SalesOrderDetailView.js +6 -3
- package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/VerkoopOrdersPage.js +39 -3
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +605 -4
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +605 -4
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +605 -4
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.js +4 -4
- package/dist-lib/integrations/supabase/types.d.ts +613 -4
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/cart-lock.functions.d.ts +11356 -0
- package/dist-lib/lib/cart-lock.functions.d.ts.map +1 -0
- package/dist-lib/lib/cart-lock.functions.js +47 -0
- package/dist-lib/lib/cart-planner.d.ts +38 -0
- package/dist-lib/lib/cart-planner.d.ts.map +1 -0
- package/dist-lib/lib/cart-planner.js +217 -0
- package/dist-lib/lib/cart-replan.functions.d.ts +22729 -0
- package/dist-lib/lib/cart-replan.functions.d.ts.map +1 -0
- package/dist-lib/lib/cart-replan.functions.js +203 -0
- package/dist-lib/lib/create-order.functions.d.ts +26999 -76
- package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
- package/dist-lib/lib/create-order.functions.js +158 -3
- package/dist-lib/lib/floriday-auto-fulfillment.functions.d.ts +34033 -0
- package/dist-lib/lib/floriday-auto-fulfillment.functions.d.ts.map +1 -0
- package/dist-lib/lib/floriday-auto-fulfillment.functions.js +65 -0
- package/dist-lib/lib/floriday-auto-fulfillment.server.d.ts +21 -0
- package/dist-lib/lib/floriday-auto-fulfillment.server.d.ts.map +1 -0
- package/dist-lib/lib/floriday-auto-fulfillment.server.js +352 -0
- package/dist-lib/lib/floriday-logistic-labels.functions.d.ts +11351 -0
- package/dist-lib/lib/floriday-logistic-labels.functions.d.ts.map +1 -0
- package/dist-lib/lib/floriday-logistic-labels.functions.js +171 -0
- package/dist-lib/lib/floriday-public.functions.d.ts +4237 -44
- package/dist-lib/lib/floriday-public.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-public.functions.js +45 -47
- package/dist-lib/lib/floriday-writes.functions.d.ts +3025 -20
- package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -1
- package/dist-lib/lib/salesorders-mapping.d.ts +2 -0
- package/dist-lib/lib/salesorders-mapping.d.ts.map +1 -1
- package/dist-lib/lib/salesorders-mapping.js +46 -20
- package/dist-lib/lib/salesorders.functions.d.ts +1831 -28
- package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
- package/dist-lib/lib/salesorders.functions.js +8 -0
- package/dist-lib/lib/tradeitems.functions.d.ts +605 -4
- package/dist-lib/lib/tradeitems.functions.d.ts.map +1 -1
- package/dist-lib/lib/useSalesOrdersQuery.d.ts +1 -0
- package/dist-lib/lib/useSalesOrdersQuery.d.ts.map +1 -1
- package/dist-lib/lib/useSalesOrdersQuery.js +121 -39
- package/package.json +1 -1
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { florydayWrite } from "./floriday-gateway.server";
|
|
2
|
+
async function loadConnectionMeta(supabase, connectionId) {
|
|
3
|
+
const { data } = await supabase
|
|
4
|
+
.from("floriday_connections")
|
|
5
|
+
.select("id, environment, access_token, api_key, is_active, gln_code, preferred_warehouse_id")
|
|
6
|
+
.eq("id", connectionId)
|
|
7
|
+
.maybeSingle();
|
|
8
|
+
return data ?? null;
|
|
9
|
+
}
|
|
10
|
+
async function loadProductPacking(supabase, tradeItemId) {
|
|
11
|
+
if (!tradeItemId)
|
|
12
|
+
return null;
|
|
13
|
+
const { data } = await supabase
|
|
14
|
+
.from("products")
|
|
15
|
+
.select("plants_per_crate, crates_per_layer, layers_per_cart")
|
|
16
|
+
.eq("trade_item_key", tradeItemId)
|
|
17
|
+
.limit(1)
|
|
18
|
+
.maybeSingle();
|
|
19
|
+
if (!data)
|
|
20
|
+
return null;
|
|
21
|
+
return {
|
|
22
|
+
plants_per_crate: Number(data.plants_per_crate) || 0,
|
|
23
|
+
crates_per_layer: Number(data.crates_per_layer) || 0,
|
|
24
|
+
layers_per_cart: Number(data.layers_per_cart) || 0,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function upsertLog(supabase, connectionId, salesOrderId, patch) {
|
|
28
|
+
return supabase.from("floriday_auto_fulfillment_log").upsert({
|
|
29
|
+
connection_id: connectionId,
|
|
30
|
+
sales_order_id: salesOrderId,
|
|
31
|
+
last_attempt_at: new Date().toISOString(),
|
|
32
|
+
...patch,
|
|
33
|
+
}, { onConflict: "connection_id,sales_order_id" });
|
|
34
|
+
}
|
|
35
|
+
async function existingFulfillmentForOrder(supabase, connectionId, salesOrderId) {
|
|
36
|
+
// Scan the most recent fulfillment orders for this connection and look for
|
|
37
|
+
// a nested loadCarrierItems entry referencing this sales order.
|
|
38
|
+
const { data } = await supabase
|
|
39
|
+
.from("floriday_fulfillment_orders_cache")
|
|
40
|
+
.select("data")
|
|
41
|
+
.eq("connection_id", connectionId)
|
|
42
|
+
.order("fetched_at", { ascending: false })
|
|
43
|
+
.limit(500);
|
|
44
|
+
const rows = data ?? [];
|
|
45
|
+
for (const row of rows) {
|
|
46
|
+
const carriers = row?.data?.loadCarriers;
|
|
47
|
+
if (!Array.isArray(carriers))
|
|
48
|
+
continue;
|
|
49
|
+
for (const c of carriers) {
|
|
50
|
+
const items = c?.loadCarrierItems;
|
|
51
|
+
if (!Array.isArray(items))
|
|
52
|
+
continue;
|
|
53
|
+
for (const it of items) {
|
|
54
|
+
if (String(it?.salesOrderId ?? "") === salesOrderId)
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
async function alreadyProcessed(supabase, connectionId, salesOrderId) {
|
|
62
|
+
const { data } = await supabase
|
|
63
|
+
.from("floriday_auto_fulfillment_log")
|
|
64
|
+
.select("status")
|
|
65
|
+
.eq("connection_id", connectionId)
|
|
66
|
+
.eq("sales_order_id", salesOrderId)
|
|
67
|
+
.maybeSingle();
|
|
68
|
+
return data?.status === "created";
|
|
69
|
+
}
|
|
70
|
+
async function loadDeliveryContext(supabase, connectionId, salesOrderId) {
|
|
71
|
+
const { data } = await supabase
|
|
72
|
+
.from("floriday_delivery_orders_cache")
|
|
73
|
+
.select("data")
|
|
74
|
+
.eq("connection_id", connectionId)
|
|
75
|
+
.eq("is_deleted", false)
|
|
76
|
+
.order("fetched_at", { ascending: false })
|
|
77
|
+
.limit(500);
|
|
78
|
+
const rows = data ?? [];
|
|
79
|
+
for (const row of rows) {
|
|
80
|
+
const d = row?.data;
|
|
81
|
+
const reqs = Array.isArray(d?.fulfillmentRequests) ? d.fulfillmentRequests : [];
|
|
82
|
+
const matching = [];
|
|
83
|
+
for (const r of reqs) {
|
|
84
|
+
if (String(r?.salesOrderId ?? "") !== salesOrderId)
|
|
85
|
+
continue;
|
|
86
|
+
matching.push({
|
|
87
|
+
fulfillmentRequestId: String(r?.fulfillmentRequestId ?? ""),
|
|
88
|
+
salesOrderId: String(r?.salesOrderId ?? ""),
|
|
89
|
+
loadCarrier: r?.loadCarrier ?? null,
|
|
90
|
+
numberOfPackages: Number(r?.numberOfPackages ?? 0) || 0,
|
|
91
|
+
deliveryRemarks: r?.deliveryRemarks ?? null,
|
|
92
|
+
tradeItemId: r?.tradeItemId ?? null,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (matching.length > 0) {
|
|
96
|
+
return {
|
|
97
|
+
deliveryOrderId: String(d?.deliveryOrderId ?? ""),
|
|
98
|
+
despatchWarehouseId: d?.despatchWarehouseId ?? null,
|
|
99
|
+
destination: d?.destination ?? null,
|
|
100
|
+
latestDeliveryDateTime: d?.deliveryDateTime ?? null,
|
|
101
|
+
requests: matching,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
function buildFulfillmentPayload(order, warehouseId, ctx) {
|
|
108
|
+
const warnings = [];
|
|
109
|
+
const supplierOrganizationId = String(order?.supplierOrganizationId ?? "");
|
|
110
|
+
const customerOrganizationId = String(order?.customerOrganizationId ?? "");
|
|
111
|
+
// Group requests by load-carrier type to build one loadCarrier per group.
|
|
112
|
+
const byCarrier = new Map();
|
|
113
|
+
for (const r of ctx.requests) {
|
|
114
|
+
const key = r.loadCarrier ?? "DANISH_TROLLEY";
|
|
115
|
+
if (!byCarrier.has(key))
|
|
116
|
+
byCarrier.set(key, []);
|
|
117
|
+
byCarrier.get(key).push(r);
|
|
118
|
+
}
|
|
119
|
+
const loadCarriers = [];
|
|
120
|
+
let sortIndex = 1;
|
|
121
|
+
for (const [carrier, requests] of byCarrier) {
|
|
122
|
+
loadCarriers.push({
|
|
123
|
+
sortIndex: sortIndex++,
|
|
124
|
+
loadCarrierType: carrier === "NONE" ? "DANISH_TROLLEY" : carrier,
|
|
125
|
+
numberOfAdditionalLayers: 0,
|
|
126
|
+
loadCarrierItems: requests.map((r, idx) => {
|
|
127
|
+
const item = {
|
|
128
|
+
sortIndex: idx + 1,
|
|
129
|
+
fulfillmentRequestId: r.fulfillmentRequestId,
|
|
130
|
+
tradeItemId: r.tradeItemId ?? String(order?.tradeItemId ?? ""),
|
|
131
|
+
salesOrderId: r.salesOrderId,
|
|
132
|
+
numberOfPackages: r.numberOfPackages,
|
|
133
|
+
};
|
|
134
|
+
const remarks = (r.deliveryRemarks ?? "").toString().trim();
|
|
135
|
+
if (remarks)
|
|
136
|
+
item.deliveryRemarks = remarks;
|
|
137
|
+
return item;
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const payload = {
|
|
142
|
+
fulfillmentOrderId: crypto.randomUUID(),
|
|
143
|
+
type: order?.tradeInstrument ?? "DIRECT_SALES",
|
|
144
|
+
despatchWarehouseId: warehouseId,
|
|
145
|
+
latestDeliveryDateTime: ctx.latestDeliveryDateTime ?? order?.delivery?.latestDeliveryDateTime ?? null,
|
|
146
|
+
supplierOrganizationId,
|
|
147
|
+
fulfillingOrganizationId: supplierOrganizationId,
|
|
148
|
+
destination: ctx.destination ?? {
|
|
149
|
+
organizationId: customerOrganizationId,
|
|
150
|
+
location: order?.delivery?.location ?? null,
|
|
151
|
+
warehouseId: null,
|
|
152
|
+
},
|
|
153
|
+
loadCarriers,
|
|
154
|
+
oneLabelOnly: false,
|
|
155
|
+
};
|
|
156
|
+
return { payload, warnings };
|
|
157
|
+
}
|
|
158
|
+
const SKIPPABLE_STATUSES = new Set(["REJECTED", "CANCELLED", "CANCELED", "EXPIRED"]);
|
|
159
|
+
export async function processOrderForAutoFulfillment(supabase, order) {
|
|
160
|
+
const salesOrderId = order.floriday_id;
|
|
161
|
+
const connectionId = order.connection_id;
|
|
162
|
+
if (order.is_deleted) {
|
|
163
|
+
await upsertLog(supabase, connectionId, salesOrderId, {
|
|
164
|
+
status: "skipped",
|
|
165
|
+
reason: "sales-order-deleted",
|
|
166
|
+
});
|
|
167
|
+
return { status: "skipped", reason: "sales-order-deleted" };
|
|
168
|
+
}
|
|
169
|
+
if (order.status && SKIPPABLE_STATUSES.has(String(order.status).toUpperCase())) {
|
|
170
|
+
await upsertLog(supabase, connectionId, salesOrderId, {
|
|
171
|
+
status: "skipped",
|
|
172
|
+
reason: `status-${order.status}`,
|
|
173
|
+
});
|
|
174
|
+
return { status: "skipped", reason: `status-${order.status}` };
|
|
175
|
+
}
|
|
176
|
+
if (await alreadyProcessed(supabase, connectionId, salesOrderId)) {
|
|
177
|
+
return { status: "skipped", reason: "already-created" };
|
|
178
|
+
}
|
|
179
|
+
if (await existingFulfillmentForOrder(supabase, connectionId, salesOrderId)) {
|
|
180
|
+
await upsertLog(supabase, connectionId, salesOrderId, {
|
|
181
|
+
status: "skipped",
|
|
182
|
+
reason: "existing-fulfillment",
|
|
183
|
+
});
|
|
184
|
+
return { status: "skipped", reason: "existing-fulfillment" };
|
|
185
|
+
}
|
|
186
|
+
const conn = await loadConnectionMeta(supabase, connectionId);
|
|
187
|
+
if (!conn) {
|
|
188
|
+
await upsertLog(supabase, connectionId, salesOrderId, {
|
|
189
|
+
status: "failed",
|
|
190
|
+
error: "connection-not-found",
|
|
191
|
+
});
|
|
192
|
+
return { status: "failed", reason: "connection-not-found" };
|
|
193
|
+
}
|
|
194
|
+
// Warehouse fallback chain:
|
|
195
|
+
// 1) connection.preferred_warehouse_id
|
|
196
|
+
// 2) salesorder.data.despatchWarehouseId
|
|
197
|
+
// 3) first non-deleted warehouse from floriday_warehouses_cache
|
|
198
|
+
let warehouseId = conn.preferred_warehouse_id ?? null;
|
|
199
|
+
let warehouseFallback = null;
|
|
200
|
+
if (!warehouseId) {
|
|
201
|
+
const orderWarehouse = String(order.data?.despatchWarehouseId ?? "").trim();
|
|
202
|
+
if (orderWarehouse) {
|
|
203
|
+
warehouseId = orderWarehouse;
|
|
204
|
+
warehouseFallback = "warehouse-fallback:order";
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (!warehouseId) {
|
|
208
|
+
const { data: wh } = await supabase
|
|
209
|
+
.from("floriday_warehouses_cache")
|
|
210
|
+
.select("floriday_id, is_default")
|
|
211
|
+
.eq("connection_id", connectionId)
|
|
212
|
+
.eq("is_deleted", false)
|
|
213
|
+
.order("is_default", { ascending: false })
|
|
214
|
+
.limit(1)
|
|
215
|
+
.maybeSingle();
|
|
216
|
+
const cached = String(wh?.floriday_id ?? "").trim();
|
|
217
|
+
if (cached) {
|
|
218
|
+
warehouseId = cached;
|
|
219
|
+
warehouseFallback = "warehouse-fallback:cache";
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (!warehouseId) {
|
|
223
|
+
await upsertLog(supabase, connectionId, salesOrderId, {
|
|
224
|
+
status: "skipped",
|
|
225
|
+
reason: "no-warehouse",
|
|
226
|
+
});
|
|
227
|
+
return { status: "skipped", reason: "no-warehouse" };
|
|
228
|
+
}
|
|
229
|
+
// Load Floriday-issued fulfillment requests from the matching delivery order.
|
|
230
|
+
const deliveryCtx = await loadDeliveryContext(supabase, connectionId, salesOrderId);
|
|
231
|
+
if (!deliveryCtx || deliveryCtx.requests.length === 0) {
|
|
232
|
+
await upsertLog(supabase, connectionId, salesOrderId, {
|
|
233
|
+
status: "skipped",
|
|
234
|
+
reason: "no-delivery-order",
|
|
235
|
+
});
|
|
236
|
+
return { status: "skipped", reason: "no-delivery-order" };
|
|
237
|
+
}
|
|
238
|
+
// Prefer the delivery order's despatchWarehouseId when Floriday supplies it.
|
|
239
|
+
const effectiveWarehouseId = deliveryCtx.despatchWarehouseId || warehouseId;
|
|
240
|
+
const { payload, warnings } = buildFulfillmentPayload(order.data, effectiveWarehouseId, deliveryCtx);
|
|
241
|
+
if (warehouseFallback && !deliveryCtx.despatchWarehouseId)
|
|
242
|
+
warnings.push(warehouseFallback);
|
|
243
|
+
// Increment attempts.
|
|
244
|
+
const { data: existing } = await supabase
|
|
245
|
+
.from("floriday_auto_fulfillment_log")
|
|
246
|
+
.select("attempts")
|
|
247
|
+
.eq("connection_id", connectionId)
|
|
248
|
+
.eq("sales_order_id", salesOrderId)
|
|
249
|
+
.maybeSingle();
|
|
250
|
+
const attempts = Number(existing?.attempts ?? 0) + 1;
|
|
251
|
+
const env = (conn.environment === "production" || conn.environment === "live" ? "live" : "staging");
|
|
252
|
+
const result = await florydayWrite(supabase, env, {
|
|
253
|
+
module: "warehouse",
|
|
254
|
+
action: "add-fulfillment-order",
|
|
255
|
+
method: "POST",
|
|
256
|
+
path: "/fulfillment-orders",
|
|
257
|
+
referenceId: salesOrderId,
|
|
258
|
+
body: payload,
|
|
259
|
+
}, null);
|
|
260
|
+
if (!result.ok) {
|
|
261
|
+
await upsertLog(supabase, connectionId, salesOrderId, {
|
|
262
|
+
status: "failed",
|
|
263
|
+
attempts,
|
|
264
|
+
error: (result.error ?? `HTTP ${result.status}`).slice(0, 500),
|
|
265
|
+
reason: warnings.join(",") || null,
|
|
266
|
+
});
|
|
267
|
+
return { status: "failed", reason: result.error };
|
|
268
|
+
}
|
|
269
|
+
const fulfillmentOrderId = String(result.data?.fulfillmentOrderId ?? result.data?.id ?? payload.fulfillmentOrderId ?? "");
|
|
270
|
+
await upsertLog(supabase, connectionId, salesOrderId, {
|
|
271
|
+
status: "created",
|
|
272
|
+
attempts,
|
|
273
|
+
fulfillment_order_id: fulfillmentOrderId || null,
|
|
274
|
+
error: null,
|
|
275
|
+
reason: warnings.join(",") || null,
|
|
276
|
+
});
|
|
277
|
+
return { status: "created", fulfillmentOrderId };
|
|
278
|
+
}
|
|
279
|
+
export async function processRecentSalesOrders(supabase, connectionId, sinceIso) {
|
|
280
|
+
// 1) Recently synced / updated sales orders in this cycle.
|
|
281
|
+
const { data: recent } = await supabase
|
|
282
|
+
.from("floriday_salesorders_cache")
|
|
283
|
+
.select("connection_id, floriday_id, status, is_deleted, data, updated_at")
|
|
284
|
+
.eq("connection_id", connectionId)
|
|
285
|
+
.gte("updated_at", sinceIso)
|
|
286
|
+
.limit(200);
|
|
287
|
+
const rowMap = new Map();
|
|
288
|
+
for (const r of (recent ?? [])) {
|
|
289
|
+
rowMap.set(r.floriday_id, r);
|
|
290
|
+
}
|
|
291
|
+
// 2) Backlog: sales orders that never got a log row, or were previously
|
|
292
|
+
// skipped/failed because the preferred warehouse wasn't set yet.
|
|
293
|
+
const { data: allOrders } = await supabase
|
|
294
|
+
.from("floriday_salesorders_cache")
|
|
295
|
+
.select("connection_id, floriday_id, status, is_deleted, data")
|
|
296
|
+
.eq("connection_id", connectionId)
|
|
297
|
+
.eq("is_deleted", false)
|
|
298
|
+
.limit(500);
|
|
299
|
+
const orderList = allOrders ?? [];
|
|
300
|
+
if (orderList.length > 0) {
|
|
301
|
+
const ids = orderList.map((o) => o.floriday_id);
|
|
302
|
+
const { data: logs } = await supabase
|
|
303
|
+
.from("floriday_auto_fulfillment_log")
|
|
304
|
+
.select("sales_order_id, status, reason")
|
|
305
|
+
.eq("connection_id", connectionId)
|
|
306
|
+
.in("sales_order_id", ids);
|
|
307
|
+
const logMap = new Map();
|
|
308
|
+
for (const l of (logs ?? [])) {
|
|
309
|
+
logMap.set(l.sales_order_id, { status: l.status, reason: l.reason });
|
|
310
|
+
}
|
|
311
|
+
for (const o of orderList) {
|
|
312
|
+
const existing = logMap.get(o.floriday_id);
|
|
313
|
+
if (!existing) {
|
|
314
|
+
rowMap.set(o.floriday_id, o);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (existing.status === "failed") {
|
|
318
|
+
rowMap.set(o.floriday_id, o);
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if (existing.status === "skipped" &&
|
|
322
|
+
(existing.reason === "no-preferred-warehouse" ||
|
|
323
|
+
existing.reason === "no-warehouse" ||
|
|
324
|
+
existing.reason === "no-delivery-order")) {
|
|
325
|
+
rowMap.set(o.floriday_id, o);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const rows = Array.from(rowMap.values());
|
|
330
|
+
let created = 0;
|
|
331
|
+
let failed = 0;
|
|
332
|
+
let skipped = 0;
|
|
333
|
+
for (const row of rows) {
|
|
334
|
+
try {
|
|
335
|
+
const r = await processOrderForAutoFulfillment(supabase, row);
|
|
336
|
+
if (r.status === "created")
|
|
337
|
+
created++;
|
|
338
|
+
else if (r.status === "failed")
|
|
339
|
+
failed++;
|
|
340
|
+
else
|
|
341
|
+
skipped++;
|
|
342
|
+
}
|
|
343
|
+
catch (err) {
|
|
344
|
+
failed++;
|
|
345
|
+
await upsertLog(supabase, row.connection_id, row.floriday_id, {
|
|
346
|
+
status: "failed",
|
|
347
|
+
error: err.message?.slice(0, 500) ?? "unknown error",
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return { processed: rows.length, created, failed, skipped };
|
|
352
|
+
}
|