@flowselections/floriday-voorraad 1.0.94 → 1.0.96

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.
Files changed (31) hide show
  1. package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -1
  2. package/dist-lib/components/voorraad/ArtikelWizard.js +21 -41
  3. package/dist-lib/components/voorraad/FloridayTakeoverPanel.d.ts.map +1 -1
  4. package/dist-lib/components/voorraad/FloridayTakeoverPanel.js +18 -1
  5. package/dist-lib/components/voorraad/StockBulkButtons.d.ts.map +1 -1
  6. package/dist-lib/components/voorraad/StockBulkButtons.js +59 -0
  7. package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
  8. package/dist-lib/components/voorraad/VoorraadTable.js +16 -1
  9. package/dist-lib/integrations/supabase/types.d.ts +282 -0
  10. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  11. package/dist-lib/lib/__tests__/product-packings.test.d.ts +2 -0
  12. package/dist-lib/lib/__tests__/product-packings.test.d.ts.map +1 -0
  13. package/dist-lib/lib/__tests__/product-packings.test.js +42 -0
  14. package/dist-lib/lib/ensure-article-codes.d.ts.map +1 -1
  15. package/dist-lib/lib/ensure-article-codes.js +2 -12
  16. package/dist-lib/lib/floriday-payload.d.ts +15 -0
  17. package/dist-lib/lib/floriday-payload.d.ts.map +1 -1
  18. package/dist-lib/lib/floriday-payload.js +36 -10
  19. package/dist-lib/lib/fusten.d.ts.map +1 -1
  20. package/dist-lib/lib/fusten.js +6 -1
  21. package/dist-lib/lib/product-packing.d.ts +8 -5
  22. package/dist-lib/lib/product-packing.d.ts.map +1 -1
  23. package/dist-lib/lib/product-packing.js +44 -36
  24. package/dist-lib/lib/product-packings.d.ts +33 -0
  25. package/dist-lib/lib/product-packings.d.ts.map +1 -0
  26. package/dist-lib/lib/product-packings.js +89 -0
  27. package/dist-lib/server-hooks/floriday-follow.d.ts.map +1 -1
  28. package/dist-lib/server-hooks/floriday-follow.js +11 -1
  29. package/package.json +1 -1
  30. package/sql/AGENTS.md +5 -0
  31. package/sql/floriday-voorraad-schema.sql +182 -5
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=product-packings.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-packings.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/product-packings.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,42 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ vi.mock("../../integrations/supabase/client", () => ({ supabase: {} }));
3
+ import { requireCompletePacking, packingNumberOrEmpty } from "../floriday-payload.js";
4
+ import { isCompletePackingRow, packingRowsFromWizard, positiveIntOrNull, primaryPacking } from "../product-packings.js";
5
+ import { floridayPackingsToRows, pickPrimaryPacking } from "../product-packing.js";
6
+ describe("verpakking: geen stille standaardwaarden", () => {
7
+ it("lege of ongeldige getallen blijven leeg", () => {
8
+ expect(positiveIntOrNull("")).toBeNull();
9
+ expect(positiveIntOrNull(undefined)).toBeNull();
10
+ expect(positiveIntOrNull(0)).toBeNull();
11
+ expect(positiveIntOrNull(2.5)).toBeNull();
12
+ expect(packingNumberOrEmpty(undefined)).toBe(0);
13
+ });
14
+ it("push weigert een onvolledige verpakking", () => {
15
+ expect(() => requireCompletePacking({ unitsPerPackage: 6, packagesPerLayer: 4 })).toThrow(/Verpakking onvolledig/);
16
+ expect(requireCompletePacking({ unitsPerPackage: 6, packagesPerLayer: 4, layersPerLoadCarrier: 8 })).toEqual({
17
+ pieces: 6, packages: 4, layers: 8,
18
+ });
19
+ });
20
+ it("Floriday-verpakking 8x4x6 (fust 306) wordt exact overgenomen", () => {
21
+ const rows = floridayPackingsToRows([
22
+ { primary: true, piecesPerPackage: 6, packagesPerLayer: 4, layersPerLoadCarrier: 8, package: { vbnPackageCode: 306 }, loadCarrier: "DANISH_TROLLEY" },
23
+ { primary: false, piecesPerPackage: 8, packagesPerLayer: 5, package: { vbnPackageCode: 408 } },
24
+ ]);
25
+ expect(rows[0]).toMatchObject({ pieces_per_package: 6, packages_per_layer: 4, layers_per_load_carrier: 8, vbn_package_code: 306, is_primary: true });
26
+ expect(rows[1]).toMatchObject({ layers_per_load_carrier: null, is_primary: false });
27
+ });
28
+ it("zonder gemarkeerde primaire verpakking wordt niet gegokt", () => {
29
+ expect(pickPrimaryPacking([{ piecesPerPackage: 6, packagesPerLayer: 4, layersPerLoadCarrier: 8 }])).toBeNull();
30
+ });
31
+ it("meerdere verpakkingen: de primaire bepaalt", () => {
32
+ const rows = packingRowsFromWizard([
33
+ { id: "a", source: "VBN", packagingType: "306", loadCarrier: "", unitsPerPackage: 6, packagesPerLayer: 4, layersPerLoadCarrier: 8, isPrimary: false, isCustomerSpecific: false, customerOrganizationIds: [] },
34
+ { id: "b", source: "VBN", packagingType: "408", loadCarrier: "", unitsPerPackage: 8, packagesPerLayer: 5, layersPerLoadCarrier: 8, isPrimary: true, isCustomerSpecific: false, customerOrganizationIds: [] },
35
+ ]);
36
+ const p = primaryPacking(rows);
37
+ expect(p?.pieces_per_package).toBe(8);
38
+ expect(p?.vbn_package_code).toBe(408);
39
+ expect(isCompletePackingRow(p)).toBe(true);
40
+ expect(isCompletePackingRow({ ...p, layers_per_load_carrier: null })).toBe(false);
41
+ });
42
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"ensure-article-codes.d.ts","sourceRoot":"","sources":["../../src/lib/ensure-article-codes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAqBnD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,SAAS,EAAE,CAAC,CAkDtB"}
1
+ {"version":3,"file":"ensure-article-codes.d.ts","sourceRoot":"","sources":["../../src/lib/ensure-article-codes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAqBnD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,SAAS,EAAE,GACjB,OAAO,CAAC,SAAS,EAAE,CAAC,CAyCtB"}
@@ -54,18 +54,8 @@ export async function ensureArticleCodes(items) {
54
54
  .update({ data: nextData, updated_at: new Date().toISOString() })
55
55
  .eq("id", it.localId);
56
56
  }
57
- else if (it.published && it.id) {
58
- // Published cache: mirror lokaal zodat volgende exports consistent zijn.
59
- const row = it.raw;
60
- const nextData = {
61
- ...(row ?? {}),
62
- supplierArticleCode: newCode,
63
- };
64
- await supabase
65
- .from("floriday_trade_items_cache")
66
- .update({ data: nextData })
67
- .eq("floriday_id", it.id);
68
- }
57
+ // Gepubliceerde artikelen: de Floriday-kopie is van Floriday-authenticatie
58
+ // en wordt hier nooit gewijzigd; de code staat alleen in de export.
69
59
  }
70
60
  catch (e) {
71
61
  // Log maar blijf doorgaan; de gegenereerde code komt sowieso in de export.
@@ -203,6 +203,21 @@ export declare function buildPrimaryPackingBase(d: WizardData): {
203
203
  loadCarrier: LoadCarrierPayload;
204
204
  photoUrl?: string;
205
205
  };
206
+ /** Verpakkingsgetal of 0 (= leeg). Geen vervangende waarde. */
207
+ export declare function packingNumberOrEmpty(v: unknown): number;
208
+ /**
209
+ * Eist een volledige verpakking (stuks per fust, fusten per laag, lagen per
210
+ * ladingdrager, elk 1–9999). Ontbreekt iets: duidelijke fout, niets aanvullen.
211
+ */
212
+ export declare function requireCompletePacking(p: {
213
+ unitsPerPackage?: unknown;
214
+ packagesPerLayer?: unknown;
215
+ layersPerLoadCarrier?: unknown;
216
+ }): {
217
+ pieces: number;
218
+ packages: number;
219
+ layers: number;
220
+ };
206
221
  export type LoadCarrierEnum = "NONE" | "AUCTION_TROLLEY" | "DANISH_TROLLEY" | "EURO_TROLLEY" | "PALLET" | "EURO_PALLET";
207
222
  export type LoadCarrierPayload = LoadCarrierEnum | number | string;
208
223
  export type PhotoTypeEnum = "UNKNOWN" | "PIECE" | "TRAY" | "DETAIL" | "RULER" | "WEBSHOPFRIENDLY" | "SCENE" | "SEASON" | "STEM" | "BUNCH" | "CONTAINER" | "CLOCK";
@@ -1 +1 @@
1
- {"version":3,"file":"floriday-payload.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-payload.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"floriday-payload.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-payload.ts"],"names":[],"mappings":"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"}
@@ -220,16 +220,41 @@ export function buildPrimaryPackingBase(d) {
220
220
  if (!vbnPackageCode && !customPackageId) {
221
221
  throw new Error("Primaire belading heeft geen geldige VBN-fust of custom package — kan aanbod niet aanmaken.");
222
222
  }
223
+ const packing = requireCompletePacking(primary);
223
224
  return {
224
- piecesPerPackage: Math.max(1, Math.min(9999, Number(primary.unitsPerPackage) || 1)),
225
- vbnPackageCode: vbnPackageCode ?? 1,
225
+ piecesPerPackage: packing.pieces,
226
+ vbnPackageCode: vbnPackageCode,
226
227
  customPackageId,
227
- packagesPerLayer: Math.max(1, Math.min(9999, Number(primary.packagesPerLayer) || 1)),
228
- layersPerLoadCarrier: Math.max(1, Math.min(9999, Number(primary.layersPerLoadCarrier) || 1)),
228
+ packagesPerLayer: packing.packages,
229
+ layersPerLoadCarrier: packing.layers,
229
230
  loadCarrier: normaliseLoadCarrier(primary.loadCarrier),
230
231
  photoUrl: primary.photoUrl,
231
232
  };
232
233
  }
234
+ // -------- Verpakking: nooit stille standaardwaarden -------------------------
235
+ /** Verpakkingsgetal of 0 (= leeg). Geen vervangende waarde. */
236
+ export function packingNumberOrEmpty(v) {
237
+ const n = Number(v);
238
+ return Number.isInteger(n) && n > 0 ? n : 0;
239
+ }
240
+ /**
241
+ * Eist een volledige verpakking (stuks per fust, fusten per laag, lagen per
242
+ * ladingdrager, elk 1–9999). Ontbreekt iets: duidelijke fout, niets aanvullen.
243
+ */
244
+ export function requireCompletePacking(p) {
245
+ const check = (v, label) => {
246
+ const n = Number(v);
247
+ if (!Number.isInteger(n) || n < 1 || n > 9999) {
248
+ throw new Error(`Verpakking onvolledig: ${label} ontbreekt of is ongeldig. Vul de verpakking aan; er is niets naar Floriday gestuurd.`);
249
+ }
250
+ return n;
251
+ };
252
+ return {
253
+ pieces: check(p.unitsPerPackage, "stuks per fust"),
254
+ packages: check(p.packagesPerLayer, "fusten per laag"),
255
+ layers: check(p.layersPerLoadCarrier, "lagen per ladingdrager"),
256
+ };
257
+ }
233
258
  const LOAD_CARRIER_VALUES = [
234
259
  "NONE", "AUCTION_TROLLEY", "DANISH_TROLLEY",
235
260
  "EURO_TROLLEY", "PALLET", "EURO_PALLET",
@@ -279,10 +304,10 @@ export function buildPackingConfigPayload(p, primary = false) {
279
304
  }
280
305
  const payload = {
281
306
  primary: Boolean(primary),
282
- piecesPerPackage: Math.max(1, Math.min(9999, Number(p.unitsPerPackage) || 1)),
307
+ piecesPerPackage: requireCompletePacking(p).pieces,
283
308
  package: pkg,
284
- packagesPerLayer: Math.max(1, Math.min(9999, Number(p.packagesPerLayer) || 1)),
285
- layersPerLoadCarrier: Math.max(1, Math.min(9999, Number(p.layersPerLoadCarrier) || 1)),
309
+ packagesPerLayer: requireCompletePacking(p).packages,
310
+ layersPerLoadCarrier: requireCompletePacking(p).layers,
286
311
  loadCarrier: normaliseLoadCarrier(p.loadCarrier),
287
312
  isHiddenForDirectSales: Boolean(p.isHiddenForDirectSales),
288
313
  };
@@ -657,9 +682,10 @@ export function floridayCacheToWizardData(raw) {
657
682
  packagingSupplierName: p?.packagingSupplierName ?? undefined,
658
683
  packagingMaterialId: customPkgId ?? undefined,
659
684
  packagingMaterialName: p?.packagingMaterialName ?? undefined,
660
- unitsPerPackage: Number(p?.piecesPerPackage ?? 1),
661
- packagesPerLayer: Number(p?.packagesPerLayer ?? 1),
662
- layersPerLoadCarrier: Number(p?.layersPerLoadCarrier ?? 1),
685
+ // Leeg (0) als Floriday geen getal heeft; nooit aanvullen.
686
+ unitsPerPackage: packingNumberOrEmpty(p?.piecesPerPackage),
687
+ packagesPerLayer: packingNumberOrEmpty(p?.packagesPerLayer),
688
+ layersPerLoadCarrier: packingNumberOrEmpty(p?.layersPerLoadCarrier),
663
689
  photoUrl: typeof p?.photoUrl === "string" ? p.photoUrl : undefined,
664
690
  isCustomerSpecific: allowed.length > 0,
665
691
  customerOrganizationIds: allowed,
@@ -1 +1 @@
1
- {"version":3,"file":"fusten.d.ts","sourceRoot":"","sources":["../../src/lib/fusten.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fusten.d.ts","sourceRoot":"","sources":["../../src/lib/fusten.ts"],"names":[],"mappings":"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"}
@@ -320,7 +320,12 @@ export async function registerSaleFustUsage(params) {
320
320
  const key = fustKeyOfRaw(packing) ?? fustKeyOf(packing);
321
321
  if (!key)
322
322
  return;
323
- const perPackage = Math.max(1, Number(packing?.piecesPerPackage ?? packing?.unitsPerPackage ?? 1) || 1);
323
+ // Geen verpakkingsgetal bekend: geen fusten afschrijven (nooit aanvullen met 1).
324
+ const perPackage = Number(packing?.piecesPerPackage ?? packing?.unitsPerPackage);
325
+ if (!Number.isInteger(perPackage) || perPackage <= 0) {
326
+ console.warn("Fusten niet afgeschreven: verpakking onvolledig", params.tradeItemKey);
327
+ return;
328
+ }
324
329
  const packages = Math.ceil(params.piecesSold / perPackage);
325
330
  if (packages <= 0)
326
331
  return;
@@ -14,15 +14,18 @@ export declare function pickPrimaryPacking(configs: unknown): ConfirmedPacking |
14
14
  /** Is de belading volledig genoeg om als "bekend" te gelden? */
15
15
  export declare function isCompletePacking(p: ConfirmedPacking | null): p is ConfirmedPacking;
16
16
  /**
17
- * Schrijft de door Floriday bevestigde belading direct op het product.
18
- * Wordt aangeroepen NA een bevestigde publicatie/teruglezing — nooit op basis
19
- * van alleen lokale invoer.
17
+ * Legt de door Floriday BEVESTIGDE verpakkingen (teruggelezen artikel) exact
18
+ * vast in `product_packings` (bron floriday). De database leidt daaruit de
19
+ * velden op het artikel af. Wordt alleen aangeroepen na een bevestigde
20
+ * teruglezing — nooit op basis van lokale invoer, nooit met aangevulde waarden.
20
21
  */
21
22
  export declare function writeConfirmedPacking(params: {
22
23
  productId: string;
23
- packing: ConfirmedPacking;
24
- source?: string;
24
+ connectionId: string;
25
+ item: any;
25
26
  }): Promise<void>;
27
+ /** Floriday `packingConfigurations` → tabelregels, exact en zonder aanvullen. */
28
+ export declare function floridayPackingsToRows(configs: unknown[]): Record<string, unknown>[];
26
29
  /** Leest de beladingsstatus van een product ("bekend" vs. "onbekend"). */
27
30
  export declare function readPackingStatus(row: Record<string, any> | null | undefined): ProductPackingStatus;
28
31
  //# sourceMappingURL=product-packing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"product-packing.d.ts","sourceRoot":"","sources":["../../src/lib/product-packing.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAClC;AAQD,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAgB5E;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,CAAC,IAAI,gBAAgB,CAEnF;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBhB;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,oBAAoB,CAcnG"}
1
+ {"version":3,"file":"product-packing.d.ts","sourceRoot":"","sources":["../../src/lib/product-packing.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAClC;AASD,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI,CAY5E;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,CAAC,IAAI,gBAAgB,CAEnF;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,GAAG,CAAC;CACX,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhB;AAED,iFAAiF;AACjF,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAkBpF;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,oBAAoB,CAcnG"}
@@ -6,11 +6,9 @@
6
6
  * standaardbelading. Bewerken in de wizard is een publicatieverzoek aan
7
7
  * Floriday, geen losse lokale kopie.
8
8
  *
9
- * Daarom schrijft dit scherm de door Floriday BEVESTIGDE belading zelf direct
10
- * weg in `products.plants_per_crate / crates_per_layer / layers_per_cart`,
11
- * zodat andere modules (logistiek, karplanning, verkoop) niet hoeven te wachten
12
- * op de 5-minuten-cron van een andere module. De bestaande trigger/cron blijft
13
- * bestaan als vangnet voor wijzigingen die buiten deze wizard om binnenkomen.
9
+ * Verpakkingen staan per product in `product_packings`; de velden
10
+ * `products.plants_per_crate / crates_per_layer / layers_per_cart / fust_type_id`
11
+ * worden door de database afgeleid van de primaire verpakking.
14
12
  *
15
13
  * De drie kolommen zijn `NOT NULL DEFAULT` (1 / 10 / 4) en worden door meerdere
16
14
  * modules gelezen; ze nullable maken zou die modules breken. In plaats daarvan
@@ -21,63 +19,73 @@
21
19
  */
22
20
  import { supabase } from "../integrations/supabase/client.js";
23
21
  function toPositiveInt(value) {
22
+ if (value === null || value === undefined || value === "")
23
+ return null;
24
24
  const n = Number(value);
25
- if (!Number.isFinite(n) || n <= 0)
25
+ if (!Number.isInteger(n) || n <= 0)
26
26
  return null;
27
- return Math.round(n);
27
+ return n;
28
28
  }
29
29
  /** Primaire belading uit een Floriday `packingConfigurations`-array. */
30
30
  export function pickPrimaryPacking(configs) {
31
31
  if (!Array.isArray(configs) || configs.length === 0)
32
32
  return null;
33
33
  const list = configs.filter((c) => c && typeof c === "object");
34
- const primary = list.find((c) => c.primary === true || c.isPrimary === true) ?? list[0];
34
+ // Alleen een gemarkeerde primaire verpakking telt; niet gokken.
35
+ const primary = list.find((c) => c.primary === true || c.isPrimary === true);
35
36
  if (!primary)
36
37
  return null;
37
38
  const pieces = toPositiveInt(primary.piecesPerPackage) ?? toPositiveInt(primary.unitsPerPackage);
38
39
  const packages = toPositiveInt(primary.packagesPerLayer);
39
40
  const layers = toPositiveInt(primary.layersPerLoadCarrier);
40
- if (pieces === null && packages === null && layers === null)
41
+ if (pieces === null || packages === null || layers === null)
41
42
  return null;
42
- return {
43
- piecesPerPackage: pieces ?? 0,
44
- packagesPerLayer: packages ?? 0,
45
- layersPerLoadCarrier: layers ?? 0,
46
- };
43
+ return { piecesPerPackage: pieces, packagesPerLayer: packages, layersPerLoadCarrier: layers };
47
44
  }
48
45
  /** Is de belading volledig genoeg om als "bekend" te gelden? */
49
46
  export function isCompletePacking(p) {
50
47
  return Boolean(p && p.piecesPerPackage > 0 && p.packagesPerLayer > 0 && p.layersPerLoadCarrier > 0);
51
48
  }
52
49
  /**
53
- * Schrijft de door Floriday bevestigde belading direct op het product.
54
- * Wordt aangeroepen NA een bevestigde publicatie/teruglezing — nooit op basis
55
- * van alleen lokale invoer.
50
+ * Legt de door Floriday BEVESTIGDE verpakkingen (teruggelezen artikel) exact
51
+ * vast in `product_packings` (bron floriday). De database leidt daaruit de
52
+ * velden op het artikel af. Wordt alleen aangeroepen na een bevestigde
53
+ * teruglezing — nooit op basis van lokale invoer, nooit met aangevulde waarden.
56
54
  */
57
55
  export async function writeConfirmedPacking(params) {
58
- const { productId, packing } = params;
59
- if (!productId || !isCompletePacking(packing))
56
+ const { productId, item } = params;
57
+ const configs = Array.isArray(item?.packingConfigurations) ? item.packingConfigurations : [];
58
+ if (!productId || configs.length === 0)
60
59
  return;
61
- const base = {
62
- plants_per_crate: packing.piecesPerPackage,
63
- crates_per_layer: packing.packagesPerLayer,
64
- layers_per_cart: packing.layersPerLoadCarrier,
65
- updated_at: new Date().toISOString(),
66
- };
67
- let { error } = await supabase
68
- .from("products")
69
- .update({
70
- ...base,
71
- floriday_packing_confirmed_at: new Date().toISOString(),
72
- floriday_packing_source: params.source ?? "wizard_publish",
73
- })
74
- .eq("id", productId);
75
- if (error && /floriday_packing_/.test(error.message ?? "")) {
76
- ({ error } = await supabase.from("products").update(base).eq("id", productId));
77
- }
60
+ const rows = floridayPackingsToRows(configs);
61
+ const { error } = await supabase.rpc("product_packings_replace", {
62
+ p_product_id: productId,
63
+ p_source: "floriday",
64
+ p_packings: rows,
65
+ });
78
66
  if (error)
79
67
  throw new Error(error.message);
80
68
  }
69
+ /** Floriday `packingConfigurations` → tabelregels, exact en zonder aanvullen. */
70
+ export function floridayPackingsToRows(configs) {
71
+ return (configs ?? [])
72
+ .filter((c) => c && typeof c === "object")
73
+ .map((raw) => {
74
+ const c = raw;
75
+ const allowed = Array.isArray(c.allowedCustomerOrganizationIds) ? c.allowedCustomerOrganizationIds : [];
76
+ return {
77
+ floriday_packing_id: c.packingConfigurationId ?? c.id ?? null,
78
+ vbn_package_code: toPositiveInt(c.package?.vbnPackageCode),
79
+ custom_package_id: c.package?.customPackageId ?? null,
80
+ load_carrier: c.loadCarrier ?? null,
81
+ pieces_per_package: toPositiveInt(c.piecesPerPackage),
82
+ packages_per_layer: toPositiveInt(c.packagesPerLayer),
83
+ layers_per_load_carrier: toPositiveInt(c.layersPerLoadCarrier),
84
+ is_primary: c.primary === true,
85
+ customer_organization_ids: allowed,
86
+ };
87
+ });
88
+ }
81
89
  /** Leest de beladingsstatus van een product ("bekend" vs. "onbekend"). */
82
90
  export function readPackingStatus(row) {
83
91
  const confirmedAt = row?.floriday_packing_confirmed_at ?? null;
@@ -0,0 +1,33 @@
1
+ import type { PackingConfigurationInput } from "./floriday-payload.js";
2
+ export declare const PACKING_INCOMPLETE_TEXT = "Verpakking onvolledig \u2013 de karindeling kan dit artikel niet plannen";
3
+ export interface ProductPackingRow {
4
+ floriday_packing_id?: string | null;
5
+ vbn_package_code?: number | null;
6
+ custom_package_id?: string | null;
7
+ fust_type_id?: string | null;
8
+ load_carrier?: string | null;
9
+ pieces_per_package: number | null;
10
+ packages_per_layer: number | null;
11
+ layers_per_load_carrier: number | null;
12
+ is_primary: boolean;
13
+ customer_organization_ids?: string[];
14
+ }
15
+ /** Positief geheel getal, anders null. Nooit een vervangende waarde. */
16
+ export declare function positiveIntOrNull(value: unknown): number | null;
17
+ export declare function isCompletePackingRow(p: Partial<ProductPackingRow> | null | undefined): boolean;
18
+ /** Kiest de primaire verpakking; zonder gemarkeerde primaire geen gok. */
19
+ export declare function primaryPacking<T extends {
20
+ is_primary: boolean;
21
+ }>(rows: T[]): T | null;
22
+ /** Wizardregels → tabelregels (eigen artikelen), zonder aanvullen. */
23
+ export declare function packingRowsFromWizard(list: PackingConfigurationInput[]): ProductPackingRow[];
24
+ /** Vervangt alle verpakkingen van een eigen artikel in één keer. */
25
+ export declare function saveOwnPackings(productId: string, rows: ProductPackingRow[]): Promise<void>;
26
+ /** Exacte kopie van de Floriday-verpakkingen voor deze artikelen. */
27
+ export declare function copyPackingsFromFloriday(client: any, connectionId: string, productIds: string[], onlyExisting?: boolean): Promise<{
28
+ copied: number;
29
+ no_packings_in_floriday: number;
30
+ }>;
31
+ /** Producten (id's) zonder volledige primaire verpakking. */
32
+ export declare function loadIncompletePackingIds(productIds: string[]): Promise<Set<string>>;
33
+ //# sourceMappingURL=product-packings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-packings.d.ts","sourceRoot":"","sources":["../../src/lib/product-packings.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAEpE,eAAO,MAAM,uBAAuB,6EACmC,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,yBAAyB,CAAC,EAAE,MAAM,EAAE,CAAC;CACtC;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAK/D;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAO9F;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,CAAC,SAAS;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAErF;AAED,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,yBAAyB,EAAE,GAAG,iBAAiB,EAAE,CAe5F;AAED,oEAAoE;AACpE,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAOjG;AAED,qEAAqE;AACrE,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,GAAG,EACX,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAAE,EACpB,YAAY,UAAQ,GACnB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,uBAAuB,EAAE,MAAM,CAAA;CAAE,CAAC,CAS9D;AAED,6DAA6D;AAC7D,wBAAsB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAYzF"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Verpakkingen per product (tabel `product_packings`, eigenaar Voorraad).
3
+ *
4
+ * - Uit Floriday overgenomen artikelen: exacte kopie van de Floriday-
5
+ * `packingConfigurations` (databasefunctie `product_packings_sync_from_floriday`).
6
+ * - Eigen artikelen: ingevoerd in de artikelwizard of de Excel-import.
7
+ * - De afgeleide velden op het artikel (plants_per_crate, crates_per_layer,
8
+ * layers_per_cart, fust_type_id) zet de database uit de PRIMAIRE verpakking.
9
+ *
10
+ * Nooit stille standaardwaarden: ontbreekt een getal, dan blijft het leeg.
11
+ */
12
+ import { supabase } from "../integrations/supabase/client.js";
13
+ export const PACKING_INCOMPLETE_TEXT = "Verpakking onvolledig – de karindeling kan dit artikel niet plannen";
14
+ /** Positief geheel getal, anders null. Nooit een vervangende waarde. */
15
+ export function positiveIntOrNull(value) {
16
+ if (value === null || value === undefined || value === "")
17
+ return null;
18
+ const n = Number(value);
19
+ if (!Number.isFinite(n) || n <= 0 || !Number.isInteger(n))
20
+ return null;
21
+ return n;
22
+ }
23
+ export function isCompletePackingRow(p) {
24
+ return Boolean(p &&
25
+ positiveIntOrNull(p.pieces_per_package) &&
26
+ positiveIntOrNull(p.packages_per_layer) &&
27
+ positiveIntOrNull(p.layers_per_load_carrier));
28
+ }
29
+ /** Kiest de primaire verpakking; zonder gemarkeerde primaire geen gok. */
30
+ export function primaryPacking(rows) {
31
+ return rows.find((r) => r.is_primary) ?? null;
32
+ }
33
+ /** Wizardregels → tabelregels (eigen artikelen), zonder aanvullen. */
34
+ export function packingRowsFromWizard(list) {
35
+ return (list ?? []).map((p) => {
36
+ const vbn = positiveIntOrNull(p.packagingType);
37
+ return {
38
+ floriday_packing_id: p.floridayId ?? null,
39
+ vbn_package_code: vbn,
40
+ custom_package_id: p.packagingMaterialId ?? null,
41
+ load_carrier: p.loadCarrier ? String(p.loadCarrier) : null,
42
+ pieces_per_package: positiveIntOrNull(p.unitsPerPackage),
43
+ packages_per_layer: positiveIntOrNull(p.packagesPerLayer),
44
+ layers_per_load_carrier: positiveIntOrNull(p.layersPerLoadCarrier),
45
+ is_primary: Boolean(p.isPrimary),
46
+ customer_organization_ids: p.customerOrganizationIds ?? [],
47
+ };
48
+ });
49
+ }
50
+ /** Vervangt alle verpakkingen van een eigen artikel in één keer. */
51
+ export async function saveOwnPackings(productId, rows) {
52
+ const { error } = await supabase.rpc("product_packings_replace", {
53
+ p_product_id: productId,
54
+ p_source: "eigen",
55
+ p_packings: rows,
56
+ });
57
+ if (error)
58
+ throw new Error(error.message);
59
+ }
60
+ /** Exacte kopie van de Floriday-verpakkingen voor deze artikelen. */
61
+ export async function copyPackingsFromFloriday(client, connectionId, productIds, onlyExisting = false) {
62
+ if (!productIds.length)
63
+ return { copied: 0, no_packings_in_floriday: 0 };
64
+ const { data, error } = await client.rpc("product_packings_sync_from_floriday", {
65
+ p_connection_id: connectionId,
66
+ p_product_ids: productIds,
67
+ p_only_existing: onlyExisting,
68
+ });
69
+ if (error)
70
+ throw new Error(error.message);
71
+ return data ?? { copied: 0, no_packings_in_floriday: 0 };
72
+ }
73
+ /** Producten (id's) zonder volledige primaire verpakking. */
74
+ export async function loadIncompletePackingIds(productIds) {
75
+ const out = new Set(productIds);
76
+ if (!productIds.length)
77
+ return out;
78
+ for (let i = 0; i < productIds.length; i += 500) {
79
+ const { data } = await supabase
80
+ .from("product_packings")
81
+ .select("product_id,pieces_per_package,packages_per_layer,layers_per_load_carrier,is_primary")
82
+ .in("product_id", productIds.slice(i, i + 500))
83
+ .eq("is_primary", true);
84
+ for (const r of (data ?? []))
85
+ if (isCompletePackingRow(r))
86
+ out.delete(r.product_id);
87
+ }
88
+ return out;
89
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"floriday-follow.d.ts","sourceRoot":"","sources":["../../src/server-hooks/floriday-follow.ts"],"names":[],"mappings":"AAwDA,4DAA4D;AAC5D,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAE9E"}
1
+ {"version":3,"file":"floriday-follow.d.ts","sourceRoot":"","sources":["../../src/server-hooks/floriday-follow.ts"],"names":[],"mappings":"AAkEA,4DAA4D;AAC5D,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAE9E"}
@@ -48,7 +48,17 @@ async function handle() {
48
48
  const { data, error } = await admin.rpc("floriday_follow_apply", { p_connection_id: conn.id, p_items: items });
49
49
  if (error)
50
50
  return json({ error: error.message }, 500);
51
- return json({ ...data, candidates: items.length, weekError: preview.weekError });
51
+ // Verpakkingen exact volgen, alleen voor artikelen die al Floriday-verpakkingen hebben
52
+ // (bestaande artikelen zonder verpakking worden pas gevuld na akkoord).
53
+ const productIds = preview.rows.filter((r) => r.productId && wanted.has(r.tradeItemId)).map((r) => r.productId);
54
+ let packings = null;
55
+ if (productIds.length) {
56
+ const { data: pk, error: pkErr } = await admin.rpc("product_packings_sync_from_floriday", {
57
+ p_connection_id: conn.id, p_product_ids: productIds, p_only_existing: true,
58
+ });
59
+ packings = pkErr ? { error: pkErr.message } : pk;
60
+ }
61
+ return json({ ...data, candidates: items.length, weekError: preview.weekError, packings });
52
62
  }
53
63
  /** Shell-handler voor /api/public/hooks/floriday-follow. */
54
64
  export async function handleFloridayFollow(request) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/floriday-voorraad",
3
- "version": "1.0.94",
3
+ "version": "1.0.96",
4
4
  "sideEffects": false,
5
5
  "type": "module",
6
6
  "main": "./dist-lib/index.js",
package/sql/AGENTS.md CHANGED
@@ -1,3 +1,8 @@
1
1
  - `floriday-voorraad-schema.sql` is generated from the database by `scripts/generate-voorraad-schema.py` (via `voorraad_schema_ddl`, service role only); regenerate after every migration and never hand-edit, because a new Shell gets its schema only from this file.
2
2
  - Voorraad owns `floriday_continuous_stock_queue_status_check`; the schema recreates it with all statuses, because other modules once recreated it without ours.
3
3
  - Schema-update order 20 (`flowselections.schema.order`); the generator keeps only own objects and wraps statements that touch other modules' tables in a to_regclass guard with a NOTICE, because Floriday-auth (30) and the Engine (60) run after Voorraad.
4
+
5
+ - `product_group_items.sort_order` is unique per group, checked deferred at commit by trigger `AA_pgi_order_taken_check` (`STRUCT_ORDER_TAKEN`; its name must sort before the internal `Unique_ConstraintTrigger_*` so the plain-language error always wins over 23505) with automatic next free order on insert, because the Engine picks group members by order and ties made the choice random.
6
+ - Stock import runs through `stock_import_create`/`_process_chunk`/`_undo_chunk` in weighted atomic portions (new articles weigh more, sizes in `inventory_recompute_limits`), never direct table writes, because one app call must stay under 8 s and undo must never overwrite later changes.
7
+ - ZERO_BATCH ignores sources IMPORT/IMPORT_UNDO and stores article code/name; the log keeps everything (deliberate bulk actions are no incidents).
8
+ - Queue cleanup: only `floriday_cleanup_stock_queue_v2` (nightly, retention in `inventory_recompute_limits`, batched, logged) and it keeps the newest skipped/failed row per article, because labels and requeue-on-price read it.