@flowselections/floriday-voorraad 1.0.27 → 1.0.29

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 (127) hide show
  1. package/dist-lib/components/voorraad/ArtikelWizard.d.ts +2 -1
  2. package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -1
  3. package/dist-lib/components/voorraad/ArtikelWizard.js +576 -324
  4. package/dist-lib/components/voorraad/EditArtikelPage.d.ts +2 -1
  5. package/dist-lib/components/voorraad/EditArtikelPage.d.ts.map +1 -1
  6. package/dist-lib/components/voorraad/EditArtikelPage.js +5 -4
  7. package/dist-lib/components/voorraad/FustenPage.d.ts +2 -0
  8. package/dist-lib/components/voorraad/FustenPage.d.ts.map +1 -0
  9. package/dist-lib/components/voorraad/FustenPage.js +97 -0
  10. package/dist-lib/components/voorraad/LogistiekTakenCard.d.ts +2 -0
  11. package/dist-lib/components/voorraad/LogistiekTakenCard.d.ts.map +1 -0
  12. package/dist-lib/components/voorraad/LogistiekTakenCard.js +54 -0
  13. package/dist-lib/components/voorraad/ProductCustomFieldsCard.d.ts +5 -0
  14. package/dist-lib/components/voorraad/ProductCustomFieldsCard.d.ts.map +1 -0
  15. package/dist-lib/components/voorraad/ProductCustomFieldsCard.js +65 -0
  16. package/dist-lib/components/voorraad/PublicatiesPage.d.ts +2 -0
  17. package/dist-lib/components/voorraad/PublicatiesPage.d.ts.map +1 -0
  18. package/dist-lib/components/voorraad/PublicatiesPage.js +60 -0
  19. package/dist-lib/components/voorraad/PublishProgressCard.d.ts +12 -0
  20. package/dist-lib/components/voorraad/PublishProgressCard.d.ts.map +1 -0
  21. package/dist-lib/components/voorraad/PublishProgressCard.js +30 -0
  22. package/dist-lib/components/voorraad/PublishReadinessCard.d.ts +10 -0
  23. package/dist-lib/components/voorraad/PublishReadinessCard.d.ts.map +1 -0
  24. package/dist-lib/components/voorraad/PublishReadinessCard.js +12 -0
  25. package/dist-lib/components/voorraad/StockBulkButtons.d.ts.map +1 -1
  26. package/dist-lib/components/voorraad/StockBulkButtons.js +65 -2
  27. package/dist-lib/components/voorraad/StockSyncStatus.d.ts +2 -0
  28. package/dist-lib/components/voorraad/StockSyncStatus.d.ts.map +1 -0
  29. package/dist-lib/components/voorraad/StockSyncStatus.js +23 -0
  30. package/dist-lib/components/voorraad/ValidationOverviewTable.d.ts.map +1 -1
  31. package/dist-lib/components/voorraad/ValidationOverviewTable.js +8 -2
  32. package/dist-lib/components/voorraad/VoorraadDashboard.d.ts.map +1 -1
  33. package/dist-lib/components/voorraad/VoorraadDashboard.js +4 -1
  34. package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
  35. package/dist-lib/components/voorraad/VoorraadPage.js +5 -1
  36. package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
  37. package/dist-lib/components/voorraad/VoorraadTable.js +10 -2
  38. package/dist-lib/components/voorraad/VoorraadVeldenCard.d.ts +2 -0
  39. package/dist-lib/components/voorraad/VoorraadVeldenCard.d.ts.map +1 -0
  40. package/dist-lib/components/voorraad/VoorraadVeldenCard.js +97 -0
  41. package/dist-lib/hooks/useFusten.d.ts +17 -0
  42. package/dist-lib/hooks/useFusten.d.ts.map +1 -0
  43. package/dist-lib/hooks/useFusten.js +81 -0
  44. package/dist-lib/hooks/useLocalTradeItems.d.ts +17 -7
  45. package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -1
  46. package/dist-lib/hooks/useLocalTradeItems.js +139 -37
  47. package/dist-lib/hooks/useLogisticsTasks.d.ts +13 -0
  48. package/dist-lib/hooks/useLogisticsTasks.d.ts.map +1 -0
  49. package/dist-lib/hooks/useLogisticsTasks.js +155 -0
  50. package/dist-lib/hooks/usePublishJob.d.ts +13 -0
  51. package/dist-lib/hooks/usePublishJob.d.ts.map +1 -0
  52. package/dist-lib/hooks/usePublishJob.js +67 -0
  53. package/dist-lib/hooks/useRegisterModuleBaseUrl.d.ts +2 -0
  54. package/dist-lib/hooks/useRegisterModuleBaseUrl.d.ts.map +1 -0
  55. package/dist-lib/hooks/useRegisterModuleBaseUrl.js +31 -0
  56. package/dist-lib/hooks/useStockSyncHealth.d.ts +8 -0
  57. package/dist-lib/hooks/useStockSyncHealth.d.ts.map +1 -0
  58. package/dist-lib/hooks/useStockSyncHealth.js +42 -0
  59. package/dist-lib/hooks/useTradeItemStock.d.ts.map +1 -1
  60. package/dist-lib/hooks/useTradeItemStock.js +37 -1
  61. package/dist-lib/hooks/useVoorraadCustomFields.d.ts +9 -0
  62. package/dist-lib/hooks/useVoorraadCustomFields.d.ts.map +1 -0
  63. package/dist-lib/hooks/useVoorraadCustomFields.js +26 -0
  64. package/dist-lib/index.d.ts +2 -0
  65. package/dist-lib/index.d.ts.map +1 -1
  66. package/dist-lib/index.js +9 -2
  67. package/dist-lib/integrations/supabase/auth-middleware.d.ts +8467 -4487
  68. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  69. package/dist-lib/integrations/supabase/client.d.ts +8467 -4487
  70. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  71. package/dist-lib/integrations/supabase/client.server.d.ts +8467 -4487
  72. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  73. package/dist-lib/integrations/supabase/types.d.ts +8714 -4631
  74. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  75. package/dist-lib/integrations/supabase/types.js +49 -0
  76. package/dist-lib/lib/floricode-required-features.functions.d.ts +8467 -4487
  77. package/dist-lib/lib/floricode-required-features.functions.d.ts.map +1 -1
  78. package/dist-lib/lib/floriday-client.d.ts +1 -1
  79. package/dist-lib/lib/floriday-client.d.ts.map +1 -1
  80. package/dist-lib/lib/floriday-client.js +1 -2
  81. package/dist-lib/lib/floriday-customer-offer.functions.d.ts +8467 -4487
  82. package/dist-lib/lib/floriday-customer-offer.functions.d.ts.map +1 -1
  83. package/dist-lib/lib/floriday-customer-offer.functions.js +14 -19
  84. package/dist-lib/lib/floriday-env.functions.d.ts +35712 -0
  85. package/dist-lib/lib/floriday-env.functions.d.ts.map +1 -0
  86. package/dist-lib/lib/floriday-env.functions.js +16 -0
  87. package/dist-lib/lib/floriday-env.server.d.ts +12 -0
  88. package/dist-lib/lib/floriday-env.server.d.ts.map +1 -1
  89. package/dist-lib/lib/floriday-env.server.js +15 -2
  90. package/dist-lib/lib/floriday-gateway.functions.d.ts +77902 -40145
  91. package/dist-lib/lib/floriday-gateway.functions.d.ts.map +1 -1
  92. package/dist-lib/lib/floriday-gateway.functions.js +12 -3
  93. package/dist-lib/lib/floriday-readiness.server.d.ts +11 -0
  94. package/dist-lib/lib/floriday-readiness.server.d.ts.map +1 -0
  95. package/dist-lib/lib/floriday-readiness.server.js +43 -0
  96. package/dist-lib/lib/floriday-vbn-required.functions.d.ts +23115 -15155
  97. package/dist-lib/lib/floriday-vbn-required.functions.d.ts.map +1 -1
  98. package/dist-lib/lib/floriday-warehouse.functions.d.ts +31362 -19422
  99. package/dist-lib/lib/floriday-warehouse.functions.d.ts.map +1 -1
  100. package/dist-lib/lib/floriday-warehouse.functions.js +3 -0
  101. package/dist-lib/lib/floriday-writes.functions.d.ts +23191 -15231
  102. package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -1
  103. package/dist-lib/lib/fusten.d.ts +87 -0
  104. package/dist-lib/lib/fusten.d.ts.map +1 -0
  105. package/dist-lib/lib/fusten.js +389 -0
  106. package/dist-lib/lib/logistics-engine.d.ts +63 -0
  107. package/dist-lib/lib/logistics-engine.d.ts.map +1 -0
  108. package/dist-lib/lib/logistics-engine.js +57 -0
  109. package/dist-lib/lib/logistics-events.d.ts +18 -0
  110. package/dist-lib/lib/logistics-events.d.ts.map +1 -0
  111. package/dist-lib/lib/logistics-events.js +61 -0
  112. package/dist-lib/lib/module-runtime-config.functions.d.ts +14 -0
  113. package/dist-lib/lib/module-runtime-config.functions.d.ts.map +1 -0
  114. package/dist-lib/lib/module-runtime-config.functions.js +107 -0
  115. package/dist-lib/lib/publish-errors.d.ts +37 -0
  116. package/dist-lib/lib/publish-errors.d.ts.map +1 -0
  117. package/dist-lib/lib/publish-errors.js +183 -0
  118. package/dist-lib/lib/publish-pipeline.d.ts +91 -0
  119. package/dist-lib/lib/publish-pipeline.d.ts.map +1 -0
  120. package/dist-lib/lib/publish-pipeline.js +212 -0
  121. package/dist-lib/lib/publish-readiness.d.ts +42 -0
  122. package/dist-lib/lib/publish-readiness.d.ts.map +1 -0
  123. package/dist-lib/lib/publish-readiness.js +102 -0
  124. package/dist-lib/lib/voorraad-custom-fields.d.ts +22 -0
  125. package/dist-lib/lib/voorraad-custom-fields.d.ts.map +1 -0
  126. package/dist-lib/lib/voorraad-custom-fields.js +71 -0
  127. package/package.json +2 -2
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Gebeurtenissen melden aan de Logistics Engine via public.logistics_events.
3
+ *
4
+ * Deze module beslist niets: ze meldt alleen dat er iets gebeurd is. De
5
+ * Engine pakt de rij op (status pending → processed), plant de keten en
6
+ * schrijft plan_run_id / error terug op dezelfde rij.
7
+ */
8
+ import { supabase } from "../integrations/supabase/client";
9
+ import { OWNER_MODULE, parseStockReservePlan, } from "./logistics-engine";
10
+ export async function insertLogisticsEvent(input) {
11
+ const { error } = await supabase.from("logistics_events").insert({
12
+ source_module: OWNER_MODULE,
13
+ event_type: input.eventType,
14
+ order_ref: input.orderRef,
15
+ strategy_id: input.strategyId ?? null,
16
+ shadow: input.shadow ?? true,
17
+ payload: (input.payload ?? {}),
18
+ });
19
+ if (error)
20
+ throw new Error(error.message);
21
+ }
22
+ /**
23
+ * Zoekt de openstaande Engine-taak die dit artikel raakt, zodat het
24
+ * stock.changed-event dezelfde order_ref (en context) draagt.
25
+ */
26
+ async function findOpenTaskFor(tradeItemKey) {
27
+ const { data } = await supabase
28
+ .from("logistics_tasks")
29
+ .select("order_ref,strategy_id,shadow,payload,buffer_ref")
30
+ .eq("owner_module", OWNER_MODULE)
31
+ .in("status", ["planned", "ready", "in_progress"])
32
+ .order("planned_start", { ascending: true });
33
+ for (const task of (data ?? [])) {
34
+ const plan = parseStockReservePlan(task.payload);
35
+ if (plan.lines.some((l) => l.tradeItemKey === tradeItemKey)) {
36
+ return { task, loadCarriers: plan.loadCarriers };
37
+ }
38
+ }
39
+ return null;
40
+ }
41
+ /** Fire-and-forget vanuit de voorraad-UI. */
42
+ export async function emitStockChangedEvent(input) {
43
+ const match = input.orderRef ? null : await findOpenTaskFor(input.tradeItemKey);
44
+ const orderRef = input.orderRef ?? match?.task.order_ref ?? null;
45
+ if (!orderRef)
46
+ return; // geen lopende order → niets te herplannen
47
+ await insertLogisticsEvent({
48
+ eventType: "stock.changed",
49
+ orderRef,
50
+ strategyId: match?.task.strategy_id ?? null,
51
+ shadow: match?.task.shadow ?? true,
52
+ payload: {
53
+ tradeItemKey: input.tradeItemKey,
54
+ physicalStock: input.physicalStock,
55
+ reservedStock: input.reservedStock,
56
+ availableStock: Math.max(0, input.physicalStock - input.reservedStock),
57
+ bufferRef: match?.task.buffer_ref ?? null,
58
+ loadCarriers: match?.loadCarriers ?? [],
59
+ },
60
+ });
61
+ }
@@ -0,0 +1,14 @@
1
+ export interface RegisterBaseUrlResult {
2
+ ok: boolean;
3
+ baseUrl: string | null;
4
+ changed: boolean;
5
+ reason?: string;
6
+ }
7
+ /**
8
+ * Idempotent: schrijft alleen wanneer de waarde daadwerkelijk wijzigt.
9
+ * Bewust zonder auth-middleware zodat de registratie ook tijdens SSR van een
10
+ * publieke shell-pagina kan slagen; er wordt niets gelezen of teruggegeven
11
+ * dat gevoelig is.
12
+ */
13
+ export declare const registerModuleBaseUrl: import("@tanstack/start-client-core").OptionalFetcher<undefined, undefined, Promise<RegisterBaseUrlResult>>;
14
+ //# sourceMappingURL=module-runtime-config.functions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-runtime-config.functions.d.ts","sourceRoot":"","sources":["../../src/lib/module-runtime-config.functions.ts"],"names":[],"mappings":"AAsEA,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,6GAqCjC,CAAC"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Zelf-registrerende basis-URL voor deze module.
3
+ *
4
+ * De cron-taak `run_floriday_continuous_stock_sync()` in Postgres bevat GEEN
5
+ * hardgecodeerde host: hij leest `module_runtime_config.voorraad_base_url`.
6
+ * Deze server-functie schrijft die waarde weg met de origin van de shell
7
+ * waarin de module op dat moment draait, zodat de voorraadsync blijft werken
8
+ * wanneer de module in een andere shell wordt gehangen.
9
+ *
10
+ * Resolutievolgorde:
11
+ * 1. PUBLIC_BASE_URL (expliciet gezet)
12
+ * 2. centrale Auth-module `/api/shell-host`
13
+ * 3. origin van het inkomende request
14
+ */
15
+ import { createServerFn } from "@tanstack/react-start";
16
+ import { getRequest } from "@tanstack/react-start/server";
17
+ const CONFIG_KEY = "voorraad_base_url";
18
+ function normalizeOrigin(raw) {
19
+ const trimmed = String(raw ?? "").trim();
20
+ if (!trimmed)
21
+ return null;
22
+ try {
23
+ const u = new URL(trimmed);
24
+ if (u.protocol !== "https:" && u.protocol !== "http:")
25
+ return null;
26
+ // Lokale dev-origins nooit registreren: pg_cron kan die niet bereiken.
27
+ const host = u.hostname.toLowerCase();
28
+ if (host === "localhost" || host === "127.0.0.1" || host === "0.0.0.0" || host.endsWith(".local")) {
29
+ return null;
30
+ }
31
+ return `${u.protocol}//${u.host}`;
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ async function resolveBaseUrl() {
38
+ const explicit = normalizeOrigin(process.env.PUBLIC_BASE_URL);
39
+ if (explicit)
40
+ return explicit;
41
+ // De hooks (/api/public/hooks/...) worden door DEZE module geserveerd,
42
+ // dus de origin van het inkomende request heeft voorrang op de shell-host.
43
+ try {
44
+ const req = getRequest();
45
+ const fromRequest = normalizeOrigin(req?.url ?? null);
46
+ if (fromRequest)
47
+ return fromRequest;
48
+ const forwardedHost = req?.headers?.get("x-forwarded-host") ?? req?.headers?.get("host");
49
+ if (forwardedHost) {
50
+ const proto = req?.headers?.get("x-forwarded-proto") ?? "https";
51
+ const fromHeaders = normalizeOrigin(`${proto}://${forwardedHost}`);
52
+ if (fromHeaders)
53
+ return fromHeaders;
54
+ }
55
+ }
56
+ catch {
57
+ // geen request-context
58
+ }
59
+ try {
60
+ const { getShellHost } = await import("./centralSecrets.server");
61
+ const host = normalizeOrigin(await getShellHost());
62
+ if (host)
63
+ return host;
64
+ }
65
+ catch {
66
+ // centrale module niet bereikbaar
67
+ }
68
+ return null;
69
+ }
70
+ /**
71
+ * Idempotent: schrijft alleen wanneer de waarde daadwerkelijk wijzigt.
72
+ * Bewust zonder auth-middleware zodat de registratie ook tijdens SSR van een
73
+ * publieke shell-pagina kan slagen; er wordt niets gelezen of teruggegeven
74
+ * dat gevoelig is.
75
+ */
76
+ export const registerModuleBaseUrl = createServerFn({ method: "POST" }).handler(async () => {
77
+ const baseUrl = await resolveBaseUrl();
78
+ if (!baseUrl) {
79
+ return { ok: false, baseUrl: null, changed: false, reason: "geen origin resolvbaar" };
80
+ }
81
+ try {
82
+ const { supabaseAdmin } = await import("../integrations/supabase/client.server");
83
+ const { data: existing } = await supabaseAdmin
84
+ .from("module_runtime_config")
85
+ .select("value")
86
+ .eq("key", CONFIG_KEY)
87
+ .maybeSingle();
88
+ if (existing?.value === baseUrl) {
89
+ return { ok: true, baseUrl, changed: false };
90
+ }
91
+ const { error } = await supabaseAdmin
92
+ .from("module_runtime_config")
93
+ .upsert({ key: CONFIG_KEY, value: baseUrl }, { onConflict: "key" });
94
+ if (error) {
95
+ return { ok: false, baseUrl, changed: false, reason: error.message };
96
+ }
97
+ return { ok: true, baseUrl, changed: true };
98
+ }
99
+ catch (e) {
100
+ return {
101
+ ok: false,
102
+ baseUrl,
103
+ changed: false,
104
+ reason: e?.message ?? String(e),
105
+ };
106
+ }
107
+ });
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Vertaalt technische foutmeldingen uit de publicatieketen naar één korte,
3
+ * begrijpelijke zin plus één concrete actie. De ruwe tekst wordt nooit aan de
4
+ * gebruiker getoond; die gaat alleen naar het publicatielogboek.
5
+ *
6
+ * Woorden als API, gateway, Floriday-intern jargon en modulenamen komen hier
7
+ * bewust niet in voor.
8
+ */
9
+ export type PublishErrorCode = "MISSING_CHARACTERISTICS" | "NO_CONNECTION" | "WRONG_ENVIRONMENT" | "NOT_LOGGED_IN" | "INVALID_VALUE" | "DUPLICATE" | "NOT_FOUND" | "TEMPORARY" | "TIMEOUT" | "RATE_LIMIT" | "UNKNOWN";
10
+ export interface PublishErrorAction {
11
+ label: string;
12
+ /** Interne route waar de gebruiker het kan oplossen. */
13
+ to?: string;
14
+ /** Wizard-stap waar het probleem zit (als het in het product zelf zit). */
15
+ stepKey?: string;
16
+ }
17
+ export interface FriendlyPublishError {
18
+ code: PublishErrorCode;
19
+ /** Eén zin, zonder jargon. */
20
+ message: string;
21
+ /** Optionele toelichting van één zin. */
22
+ hint?: string;
23
+ action?: PublishErrorAction;
24
+ /** Mag automatisch opnieuw geprobeerd worden. */
25
+ retryable: boolean;
26
+ /** Ontbrekende eigenschapscodes, indien van toepassing. */
27
+ missingCodes?: string[];
28
+ /** Ruwe technische tekst — alleen voor het logboek. */
29
+ detail: string;
30
+ }
31
+ /** Labels voor bekende eigenschapscodes, zodat de melding leesbaar blijft. */
32
+ export declare function describeCodes(codes: string[], labels?: Record<string, string>): string;
33
+ export declare function translatePublishError(error: unknown, opts?: {
34
+ characteristicLabels?: Record<string, string>;
35
+ }): FriendlyPublishError;
36
+ export declare function friendlyFieldName(field?: string): string;
37
+ //# sourceMappingURL=publish-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish-errors.d.ts","sourceRoot":"","sources":["../../src/lib/publish-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,gBAAgB,GACxB,yBAAyB,GACzB,eAAe,GACf,mBAAmB,GACnB,eAAe,GACf,eAAe,GACf,WAAW,GACX,WAAW,GACX,WAAW,GACX,SAAS,GACT,YAAY,GACZ,SAAS,CAAC;AAEd,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,gBAAgB,CAAC;IACvB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,iDAAiD;IACjD,SAAS,EAAE,OAAO,CAAC;IACnB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAiBD,8EAA8E;AAC9E,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EAAE,EACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,MAAM,CAIR;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;IAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACvD,oBAAoB,CAyItB;AAgBD,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAGxD"}
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Vertaalt technische foutmeldingen uit de publicatieketen naar één korte,
3
+ * begrijpelijke zin plus één concrete actie. De ruwe tekst wordt nooit aan de
4
+ * gebruiker getoond; die gaat alleen naar het publicatielogboek.
5
+ *
6
+ * Woorden als API, gateway, Floriday-intern jargon en modulenamen komen hier
7
+ * bewust niet in voor.
8
+ */
9
+ const MISSING_RE = /MISSING_CHARACTERISTICS:([A-Z0-9,]+):/;
10
+ function extractMissingCodes(raw) {
11
+ const tagged = raw.match(MISSING_RE);
12
+ if (tagged)
13
+ return tagged[1].split(",").filter(Boolean);
14
+ const idx = raw.toLowerCase().indexOf("missing characteristics are:");
15
+ if (idx < 0)
16
+ return [];
17
+ const tail = raw.slice(idx);
18
+ const codes = new Set();
19
+ const re = /\b([A-Z]\d{1,4})\b/g;
20
+ let m;
21
+ while ((m = re.exec(tail)) !== null)
22
+ codes.add(m[1].toUpperCase());
23
+ return Array.from(codes);
24
+ }
25
+ /** Labels voor bekende eigenschapscodes, zodat de melding leesbaar blijft. */
26
+ export function describeCodes(codes, labels) {
27
+ return codes
28
+ .map((c) => (labels?.[c] ? `${labels[c]}` : c))
29
+ .join(", ");
30
+ }
31
+ export function translatePublishError(error, opts) {
32
+ const detail = error instanceof Error
33
+ ? error.message
34
+ : typeof error === "string"
35
+ ? error
36
+ : JSON.stringify(error ?? {});
37
+ const raw = detail ?? "";
38
+ const lower = raw.toLowerCase();
39
+ const missingCodes = extractMissingCodes(raw);
40
+ if (missingCodes.length > 0) {
41
+ const readable = describeCodes(missingCodes, opts?.characteristicLabels);
42
+ return {
43
+ code: "MISSING_CHARACTERISTICS",
44
+ message: `Voor dit product zijn nog gegevens nodig: ${readable}.`,
45
+ hint: "Vul deze eigenschappen in en publiceer opnieuw.",
46
+ action: { label: "Invullen", stepKey: "eigenschappen" },
47
+ retryable: false,
48
+ missingCodes,
49
+ detail: raw,
50
+ };
51
+ }
52
+ if (lower.includes("no_active_floriday_connection") ||
53
+ lower.includes("geen actieve floriday-koppeling") ||
54
+ lower.includes("geen actieve koppeling") ||
55
+ lower.includes("geen actieve floriday-connectie")) {
56
+ return {
57
+ code: "NO_CONNECTION",
58
+ message: "De verbinding met de handelsomgeving is niet actief.",
59
+ hint: "Controleer de verbinding in de instellingen en probeer het opnieuw.",
60
+ action: { label: "Naar Instellingen", to: "/instellingen" },
61
+ retryable: false,
62
+ detail: raw,
63
+ };
64
+ }
65
+ if (lower.includes("invalid_floriday_environment") ||
66
+ lower.includes("ongeldige environment") ||
67
+ (lower.includes("staging") && lower.includes("live"))) {
68
+ return {
69
+ code: "WRONG_ENVIRONMENT",
70
+ message: "De gekozen werkomgeving komt niet overeen met de verbinding.",
71
+ hint: "Kies in de instellingen dezelfde omgeving als de verbinding.",
72
+ action: { label: "Naar Instellingen", to: "/instellingen" },
73
+ retryable: false,
74
+ detail: raw,
75
+ };
76
+ }
77
+ if (lower.includes("unauthorized") || lower.includes(" 401")) {
78
+ return {
79
+ code: "NOT_LOGGED_IN",
80
+ message: "Je bent niet meer aangemeld.",
81
+ hint: "Meld je opnieuw aan en publiceer daarna verder.",
82
+ action: { label: "Opnieuw aanmelden", to: "/login" },
83
+ retryable: false,
84
+ detail: raw,
85
+ };
86
+ }
87
+ if (lower.includes("429") || lower.includes("rate limit") || lower.includes("too many")) {
88
+ return {
89
+ code: "RATE_LIMIT",
90
+ message: "Het is nu erg druk bij de handelsomgeving.",
91
+ hint: "We proberen het automatisch nog een paar keer.",
92
+ retryable: true,
93
+ detail: raw,
94
+ };
95
+ }
96
+ if (lower.includes("timeout") ||
97
+ lower.includes("timed out") ||
98
+ lower.includes("network") ||
99
+ lower.includes("failed to fetch") ||
100
+ lower.includes("niet-json") ||
101
+ /\b5\d\d\b/.test(raw)) {
102
+ return {
103
+ code: "TEMPORARY",
104
+ message: "De handelsomgeving reageerde even niet.",
105
+ hint: "We proberen het automatisch opnieuw.",
106
+ retryable: true,
107
+ detail: raw,
108
+ };
109
+ }
110
+ if (lower.includes("already exists") || lower.includes("duplicate") || lower.includes(" 409")) {
111
+ return {
112
+ code: "DUPLICATE",
113
+ message: "Dit product bestaat al in de handelsomgeving.",
114
+ hint: "Open het bestaande product en werk dat bij.",
115
+ retryable: false,
116
+ detail: raw,
117
+ };
118
+ }
119
+ if (lower.includes("not found") || lower.includes(" 404")) {
120
+ return {
121
+ code: "NOT_FOUND",
122
+ message: "Het product kon niet worden teruggevonden in de handelsomgeving.",
123
+ hint: "Probeer opnieuw te publiceren; blijft dit staan, maak het product dan opnieuw aan.",
124
+ retryable: false,
125
+ detail: raw,
126
+ };
127
+ }
128
+ const fieldMatch = raw.match(/'([A-Za-z0-9_.]+)'\s+(?:is|must|should|cannot)/) ??
129
+ raw.match(/field\s+'?([A-Za-z0-9_.]+)'?/i);
130
+ if (lower.includes(" 400") || lower.includes("validation") || lower.includes("invalid")) {
131
+ const field = fieldMatch?.[1];
132
+ return {
133
+ code: "INVALID_VALUE",
134
+ message: field
135
+ ? `De ingevulde waarde bij "${friendlyFieldName(field)}" wordt niet geaccepteerd.`
136
+ : "Een van de ingevulde waarden wordt niet geaccepteerd.",
137
+ hint: "Pas de waarde aan en publiceer opnieuw.",
138
+ action: { label: "Controleren", stepKey: stepForFieldName(field) },
139
+ retryable: false,
140
+ detail: raw,
141
+ };
142
+ }
143
+ return {
144
+ code: "UNKNOWN",
145
+ message: "Het publiceren is niet gelukt.",
146
+ hint: "Probeer het opnieuw. Blijft dit gebeuren, geef dan het referentienummer door aan support.",
147
+ retryable: false,
148
+ detail: raw,
149
+ };
150
+ }
151
+ const FIELD_LABELS = {
152
+ tradeItemName: "Artikelnaam",
153
+ name: "Artikelnaam",
154
+ vbnProductCode: "Productsoort",
155
+ botanicalNames: "Botanische naam",
156
+ countryOfOriginIsoCodes: "Land van herkomst",
157
+ countryOfOrigin: "Land van herkomst",
158
+ characteristics: "Eigenschappen",
159
+ packingConfigurations: "Belading",
160
+ photos: "Foto's",
161
+ supplierArticleCode: "Artikelcode",
162
+ articleGtin: "Barcode",
163
+ };
164
+ export function friendlyFieldName(field) {
165
+ if (!field)
166
+ return "een veld";
167
+ return FIELD_LABELS[field] ?? field;
168
+ }
169
+ function stepForFieldName(field) {
170
+ if (!field)
171
+ return undefined;
172
+ if (["botanicalNames", "countryOfOrigin", "countryOfOriginIsoCodes"].includes(field))
173
+ return "paspoort";
174
+ if (field === "characteristics")
175
+ return "eigenschappen";
176
+ if (field === "packingConfigurations")
177
+ return "belading";
178
+ if (field === "photos")
179
+ return "fotos";
180
+ if (field === "vbnProductCode")
181
+ return "vbn";
182
+ return "artikel";
183
+ }
@@ -0,0 +1,91 @@
1
+ import { type FriendlyPublishError } from "./publish-errors";
2
+ export type PublishStepKey = "trade-item" | "stock" | "offer" | "supply-line" | "prices" | "verify";
3
+ export declare const PUBLISH_STEPS: {
4
+ key: PublishStepKey;
5
+ label: string;
6
+ }[];
7
+ export type PublishStepStatus = "pending" | "running" | "done" | "failed" | "skipped";
8
+ export interface PublishStepRow {
9
+ id: string;
10
+ job_id: string;
11
+ step_key: PublishStepKey;
12
+ label: string;
13
+ position: number;
14
+ status: PublishStepStatus;
15
+ attempts: number;
16
+ error_code: string | null;
17
+ error_message: string | null;
18
+ error_detail: string | null;
19
+ result: any;
20
+ started_at: string | null;
21
+ finished_at: string | null;
22
+ }
23
+ export type PublishJobStatus = "running" | "succeeded" | "succeeded_with_warnings" | "failed";
24
+ export interface PublishJobRow {
25
+ id: string;
26
+ user_id: string;
27
+ connection_id: string | null;
28
+ environment: string;
29
+ product_id: string | null;
30
+ trade_item_id: string | null;
31
+ trade_item_key: string | null;
32
+ intent: "create" | "update";
33
+ status: PublishJobStatus;
34
+ reference_code: string;
35
+ title: string | null;
36
+ summary: any;
37
+ snapshot: any;
38
+ finished_at: string | null;
39
+ created_at: string;
40
+ updated_at: string;
41
+ }
42
+ export declare function createPublishJob(input: {
43
+ connectionId: string | null;
44
+ environment: string;
45
+ intent: "create" | "update";
46
+ title: string;
47
+ productId?: string | null;
48
+ tradeItemId?: string | null;
49
+ tradeItemKey?: string | null;
50
+ snapshot?: unknown;
51
+ activeSteps?: PublishStepKey[];
52
+ }): Promise<PublishJobRow | null>;
53
+ export declare function loadPublishJob(jobId: string): Promise<{
54
+ job: PublishJobRow | null;
55
+ steps: PublishStepRow[];
56
+ }>;
57
+ export declare function markStepSkipped(jobId: string, key: PublishStepKey): Promise<void>;
58
+ export interface RunStepResult<T> {
59
+ ok: boolean;
60
+ value?: T;
61
+ error?: FriendlyPublishError;
62
+ skipped?: boolean;
63
+ }
64
+ /**
65
+ * Voert één deelstap uit. Al geslaagde stappen worden overgeslagen zodat
66
+ * "opnieuw proberen" nooit dubbel publiceert. Tijdelijke storingen worden
67
+ * automatisch tot 3× herhaald met oplopende wachttijd.
68
+ */
69
+ export declare function runPublishStep<T>(jobId: string | null, key: PublishStepKey, fn: () => Promise<T>, opts?: {
70
+ maxAttempts?: number;
71
+ characteristicLabels?: Record<string, string>;
72
+ }): Promise<RunStepResult<T>>;
73
+ export declare function finishPublishJob(jobId: string, patch?: {
74
+ tradeItemId?: string | null;
75
+ summary?: unknown;
76
+ }): Promise<PublishJobStatus>;
77
+ /**
78
+ * Onthoudt welke gegevens door de handelsomgeving zijn afgekeurd, zodat een
79
+ * volgend product hier vóór het publiceren al op gecontroleerd wordt.
80
+ */
81
+ export declare function rememberPublishRejection(input: {
82
+ vbnCode: string;
83
+ scope: "characteristic" | "field";
84
+ keys: string[];
85
+ lastError?: string;
86
+ }): Promise<void>;
87
+ export declare function listPublishLearnings(vbnCode: string | null | undefined): Promise<{
88
+ scope: string;
89
+ field_key: string;
90
+ }[]>;
91
+ //# sourceMappingURL=publish-pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish-pipeline.d.ts","sourceRoot":"","sources":["../../src/lib/publish-pipeline.ts"],"names":[],"mappings":"AAQA,OAAO,EAAyB,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAEpF,MAAM,MAAM,cAAc,GACtB,YAAY,GACZ,OAAO,GACP,OAAO,GACP,aAAa,GACb,QAAQ,GACR,QAAQ,CAAC;AAEb,eAAO,MAAM,aAAa,EAAE;IAAE,GAAG,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAOjE,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,SAAS,GACT,MAAM,GACN,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,GAAG,CAAC;IACZ,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,WAAW,GACX,yBAAyB,GACzB,QAAQ,CAAC;AAEb,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,MAAM,EAAE,gBAAgB,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,GAAG,CAAC;IACb,QAAQ,EAAE,GAAG,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAKD,wBAAsB,gBAAgB,CAAC,KAAK,EAAE;IAC5C,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,cAAc,EAAE,CAAC;CAChC,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAiChC;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3D,GAAG,EAAE,aAAa,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB,CAAC,CASD;AAUD,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,iBAEvE;AAID,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,GAAG,EAAE,cAAc,EACnB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC7E,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAsD3B;AAeD,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACzD,OAAO,CAAC,gBAAgB,CAAC,CAmB3B;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,KAAK,EAAE;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC;IAClC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BhB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACjC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAOjD"}