@flowselections/floriday-verkoop-module 1.0.14 → 1.0.16
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/CreateOrderPage.d.ts.map +1 -1
- package/dist-lib/components/verkoop/CreateOrderPage.js +34 -20
- package/dist-lib/components/verkoop/SearchableSelect.d.ts +1 -0
- package/dist-lib/components/verkoop/SearchableSelect.d.ts.map +1 -1
- package/dist-lib/components/verkoop/SearchableSelect.js +1 -1
- package/dist-lib/lib/create-order.functions.d.ts +10 -2
- package/dist-lib/lib/create-order.functions.d.ts.map +1 -1
- package/dist-lib/lib/create-order.functions.js +102 -19
- package/package.json +3 -3
|
@@ -16,30 +16,76 @@ export const listCustomersForCreateOrder = createServerFn({ method: "GET" })
|
|
|
16
16
|
.range(0, 4999);
|
|
17
17
|
return { items: data ?? [] };
|
|
18
18
|
});
|
|
19
|
-
// ─── Producten (
|
|
19
|
+
// ─── Producten (uit voorraadmodule: alle actieve Floriday trade items) ─────
|
|
20
|
+
// Bron = zelfde data als de Voorraad-pagina: floriday_trade_items_cache
|
|
21
|
+
// gejoined met trade_item_stock. Items zonder voorraad worden ook getoond
|
|
22
|
+
// (grijs in de UI, met melding "niet op voorraad"), zodat gebruikers ook
|
|
23
|
+
// vooruit kunnen bestellen op verwachte voorraad.
|
|
20
24
|
export const listProductsForCreateOrder = createServerFn({ method: "GET" })
|
|
21
25
|
.middleware([requireSupabaseAuth])
|
|
22
26
|
.handler(async ({ context }) => {
|
|
23
|
-
const
|
|
24
|
-
.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
const [tradeItemsRes, stockRes] = await Promise.all([
|
|
28
|
+
context.supabase
|
|
29
|
+
.from("floriday_trade_items_cache")
|
|
30
|
+
.select("floriday_id, data")
|
|
31
|
+
.eq("is_deleted", false)
|
|
32
|
+
.range(0, 4999),
|
|
33
|
+
context.supabase
|
|
34
|
+
.from("trade_item_stock")
|
|
35
|
+
.select("trade_item_key, physical_stock, reserved_stock, incoming_stock"),
|
|
36
|
+
]);
|
|
37
|
+
const tradeItems = tradeItemsRes.data;
|
|
38
|
+
const stockRows = stockRes.data;
|
|
39
|
+
const stockByKey = new Map();
|
|
27
40
|
for (const s of Array.isArray(stockRows) ? stockRows : []) {
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
41
|
+
const k = s?.trade_item_key;
|
|
42
|
+
if (typeof k !== "string")
|
|
43
|
+
continue;
|
|
44
|
+
stockByKey.set(k, {
|
|
45
|
+
physical: Number(s.physical_stock ?? 0),
|
|
46
|
+
reserved: Number(s.reserved_stock ?? 0),
|
|
47
|
+
incoming: Number(s.incoming_stock ?? 0),
|
|
48
|
+
});
|
|
32
49
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
.
|
|
39
|
-
|
|
40
|
-
const items = (Array.isArray(
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
const pickName = (n) => {
|
|
51
|
+
if (!n)
|
|
52
|
+
return "";
|
|
53
|
+
if (typeof n === "string")
|
|
54
|
+
return n;
|
|
55
|
+
return String(n.nl ?? n.en ?? n.de ?? Object.values(n)[0] ?? "");
|
|
56
|
+
};
|
|
57
|
+
const items = (Array.isArray(tradeItems) ? tradeItems : [])
|
|
58
|
+
.map((r) => {
|
|
59
|
+
const d = r?.data ?? {};
|
|
60
|
+
const name = pickName(d.tradeItemName) || d.tradeItemReference || "(naamloos)";
|
|
61
|
+
const packs = Array.isArray(d.packingConfigurations) ? d.packingConfigurations : [];
|
|
62
|
+
const primary = packs.find((p) => p?.primary) ?? packs[0] ?? {};
|
|
63
|
+
const ppc = Math.max(1, Number(primary?.piecesPerPackage ?? 1));
|
|
64
|
+
const cpl = Math.max(1, Number(primary?.packagesPerLayer ?? 1));
|
|
65
|
+
const lpc = Math.max(1, Number(primary?.layersPerLoadCarrier ?? 1));
|
|
66
|
+
const stock = stockByKey.get(r.floriday_id);
|
|
67
|
+
const physical = stock?.physical ?? 0;
|
|
68
|
+
const reserved = stock?.reserved ?? 0;
|
|
69
|
+
const available = Math.max(0, physical - reserved);
|
|
70
|
+
return {
|
|
71
|
+
id: r.floriday_id,
|
|
72
|
+
product: name,
|
|
73
|
+
article_code: d.supplierArticleCode ?? null,
|
|
74
|
+
unit: "stuks",
|
|
75
|
+
sale_price: null,
|
|
76
|
+
plants_per_crate: ppc,
|
|
77
|
+
crates_per_layer: cpl,
|
|
78
|
+
layers_per_cart: lpc,
|
|
79
|
+
physical_stock: physical,
|
|
80
|
+
reserved_stock: reserved,
|
|
81
|
+
available_stock: available,
|
|
82
|
+
in_stock: available > 0,
|
|
83
|
+
};
|
|
84
|
+
})
|
|
85
|
+
.sort((a, b) => {
|
|
86
|
+
if (a.in_stock !== b.in_stock)
|
|
87
|
+
return a.in_stock ? -1 : 1;
|
|
88
|
+
return a.product.localeCompare(b.product, "nl");
|
|
43
89
|
});
|
|
44
90
|
return { items };
|
|
45
91
|
});
|
|
@@ -114,6 +160,11 @@ const LineInput = z.object({
|
|
|
114
160
|
quantity: z.number().int().positive(), // aantal PLANTEN (== fusten * plants_per_crate)
|
|
115
161
|
unit: z.string().max(50).nullable().optional(),
|
|
116
162
|
unit_price: z.number().nonnegative().optional(),
|
|
163
|
+
// Packing-info uit voorraadmodule; nodig om ontbrekende products-rij aan te maken
|
|
164
|
+
plants_per_crate: z.number().int().positive().optional(),
|
|
165
|
+
crates_per_layer: z.number().int().positive().optional(),
|
|
166
|
+
layers_per_cart: z.number().int().positive().optional(),
|
|
167
|
+
article_code: z.string().max(100).nullable().optional(),
|
|
117
168
|
});
|
|
118
169
|
const CreateManualOrderInput = z.object({
|
|
119
170
|
customerId: z.string().uuid(),
|
|
@@ -152,6 +203,38 @@ export const createManualOrder = createServerFn({ method: "POST" })
|
|
|
152
203
|
throw new Error(`Leverdatum (${data.deliveryDate}) ligt voor de eerst mogelijke datum (${earliestISO}) o.b.v. orderpicktijd (${pickDays}d) + levertijd vervoerder (${carrierDeliveryDays}d).`);
|
|
153
204
|
}
|
|
154
205
|
const { supabaseAdmin } = await import("../integrations/supabase/client.server");
|
|
206
|
+
// Zorg dat elk product_id (= trade_item_key uit voorraad) een rij in
|
|
207
|
+
// `products` heeft — de order_items FK vereist dit én de karindeling
|
|
208
|
+
// (planAndSaveAutoCarts) joined op products voor de packing-waarden.
|
|
209
|
+
const productIds = Array.from(new Set(data.lines.map((l) => l.product_id)));
|
|
210
|
+
const { data: existingProducts } = await supabaseAdmin
|
|
211
|
+
.from("products").select("id").in("id", productIds);
|
|
212
|
+
const existingIds = new Set((existingProducts ?? []).map((p) => p.id));
|
|
213
|
+
const missingLines = data.lines.filter((l) => !existingIds.has(l.product_id));
|
|
214
|
+
if (missingLines.length > 0) {
|
|
215
|
+
const seen = new Set();
|
|
216
|
+
const toInsert = missingLines.filter((l) => {
|
|
217
|
+
if (seen.has(l.product_id))
|
|
218
|
+
return false;
|
|
219
|
+
seen.add(l.product_id);
|
|
220
|
+
return true;
|
|
221
|
+
}).map((l) => ({
|
|
222
|
+
id: l.product_id,
|
|
223
|
+
product: l.product_name,
|
|
224
|
+
batch: "",
|
|
225
|
+
location: "",
|
|
226
|
+
unit: l.unit ?? "stuks",
|
|
227
|
+
plants_per_crate: Math.max(1, Number(l.plants_per_crate ?? 1)),
|
|
228
|
+
crates_per_layer: Math.max(1, Number(l.crates_per_layer ?? 1)),
|
|
229
|
+
layers_per_cart: Math.max(1, Number(l.layers_per_cart ?? 1)),
|
|
230
|
+
sale_price: l.unit_price ?? null,
|
|
231
|
+
trade_item_key: l.product_id,
|
|
232
|
+
custom_fields: { floriday_id: l.product_id, source: "auto-from-voorraad" },
|
|
233
|
+
}));
|
|
234
|
+
const { error: prodErr } = await supabaseAdmin.from("products").insert(toInsert);
|
|
235
|
+
if (prodErr)
|
|
236
|
+
throw new Error(`Product aanmaken faalde: ${prodErr.message}`);
|
|
237
|
+
}
|
|
155
238
|
const total = data.lines.reduce((s, l) => s + (Number(l.unit_price ?? 0) * Number(l.quantity)), 0);
|
|
156
239
|
const { data: order, error: orderErr } = await supabaseAdmin.from("orders").insert({
|
|
157
240
|
customer_name: data.customerName,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowselections/floriday-verkoop-module",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.16",
|
|
4
4
|
"private": false,
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"lint": "eslint ."
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@flowselections/core": "
|
|
32
|
+
"@flowselections/core": "1.0.12",
|
|
33
33
|
"@tanstack/react-query": "^5.0.0",
|
|
34
34
|
"@tanstack/react-router": "^1.0.0",
|
|
35
35
|
"@tanstack/react-start": "^1.0.0",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@cloudflare/vite-plugin": "^1.25.5",
|
|
48
48
|
"@eslint/js": "^9.32.0",
|
|
49
|
-
"@flowselections/core": "
|
|
49
|
+
"@flowselections/core": "1.0.12",
|
|
50
50
|
"@lovable.dev/vite-tanstack-config": "2.6.4",
|
|
51
51
|
"@rsbuild/core": "^1.0.0",
|
|
52
52
|
"@tailwindcss/vite": "^4.2.1",
|