@flowselections/floriday-voorraad 1.0.121 → 1.0.125
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/voorraad/ArtikelWizard.d.ts +14 -1
- package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/ArtikelWizard.js +88 -26
- package/dist-lib/components/voorraad/FloridayInfoCard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/FloridayInfoCard.js +4 -2
- package/dist-lib/components/voorraad/FloridayLoadCarriers.d.ts.map +1 -1
- package/dist-lib/components/voorraad/FloridayLoadCarriers.js +3 -2
- package/dist-lib/components/voorraad/NieuwArtikelPage.d.ts.map +1 -1
- package/dist-lib/components/voorraad/NieuwArtikelPage.js +72 -6
- package/dist-lib/components/voorraad/PublishProgressCard.d.ts +7 -0
- package/dist-lib/components/voorraad/PublishProgressCard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/PublishProgressCard.js +22 -1
- package/dist-lib/components/voorraad/StockSyncStatus.js +1 -1
- package/dist-lib/hooks/useLoadCarriers.d.ts +12 -0
- package/dist-lib/hooks/useLoadCarriers.d.ts.map +1 -0
- package/dist-lib/hooks/useLoadCarriers.js +49 -0
- package/dist-lib/hooks/usePublishJob.d.ts +1 -0
- package/dist-lib/hooks/usePublishJob.d.ts.map +1 -1
- package/dist-lib/hooks/usePublishJob.js +20 -1
- package/dist-lib/hooks/useStockSyncHealth.d.ts +3 -1
- package/dist-lib/hooks/useStockSyncHealth.d.ts.map +1 -1
- package/dist-lib/hooks/useStockSyncHealth.js +68 -19
- package/dist-lib/integrations/supabase/types.d.ts +192 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/__tests__/erp-test-123.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/erp-test-123.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/erp-test-123.test.js +43 -0
- package/dist-lib/lib/__tests__/load-carriers.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/load-carriers.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/load-carriers.test.js +15 -0
- package/dist-lib/lib/buyer-organizations.d.ts +26 -0
- package/dist-lib/lib/buyer-organizations.d.ts.map +1 -0
- package/dist-lib/lib/buyer-organizations.js +41 -0
- package/dist-lib/lib/floriday-customer-offer.functions.d.ts +4 -0
- package/dist-lib/lib/floriday-customer-offer.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-customer-offer.functions.js +54 -16
- package/dist-lib/lib/floriday-info.d.ts +0 -1
- package/dist-lib/lib/floriday-info.d.ts.map +1 -1
- package/dist-lib/lib/floriday-info.js +0 -8
- package/dist-lib/lib/simple-packing.d.ts +31 -0
- package/dist-lib/lib/simple-packing.d.ts.map +1 -0
- package/dist-lib/lib/simple-packing.js +62 -0
- package/package.json +1 -1
- package/sql/AGENTS.md +2 -1
- package/sql/floriday-voorraad-schema.sql +328 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"erp-test-123.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/erp-test-123.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { resolveBuyerOrganizations, isMissingFunctionError } from "../buyer-organizations.js";
|
|
3
|
+
import { missingPackingFields, simplePackingToRow, engineOordeelRegel, ENGINE_CARRIER_CODE } from "../simple-packing.js";
|
|
4
|
+
const cache = async () => ["cache-1"];
|
|
5
|
+
describe("kopers: vaste zoekvolgorde", () => {
|
|
6
|
+
it("expliciete keuze gaat voor alles", async () => {
|
|
7
|
+
const r = await resolveBuyerOrganizations({ explicit: ["a"], priceGroupCustomers: ["b"], authFunction: ["c"], connectionsCache: cache });
|
|
8
|
+
expect(r).toMatchObject({ ids: ["a"], source: "keuze" });
|
|
9
|
+
});
|
|
10
|
+
it("zonder keuze: klanten van de prijsgroep", async () => {
|
|
11
|
+
const r = await resolveBuyerOrganizations({ explicit: [], priceGroupCustomers: ["b", "b", "b2"], authFunction: ["c"], connectionsCache: cache });
|
|
12
|
+
expect(r).toMatchObject({ ids: ["b", "b2"], source: "prijsgroep" });
|
|
13
|
+
});
|
|
14
|
+
it("daarna floriday_buyer_organizations, ook als die leeg is (geen terugval op de oude cache)", async () => {
|
|
15
|
+
const r = await resolveBuyerOrganizations({ explicit: [], priceGroupCustomers: [], authFunction: [], connectionsCache: cache });
|
|
16
|
+
expect(r.source).toBe("geen");
|
|
17
|
+
expect(r.ids).toEqual([]);
|
|
18
|
+
});
|
|
19
|
+
it("alleen als de functie nog niet bestaat: de oude koppelingscache", async () => {
|
|
20
|
+
const r = await resolveBuyerOrganizations({ explicit: [], priceGroupCustomers: [], authFunction: null, connectionsCache: cache });
|
|
21
|
+
expect(r).toMatchObject({ ids: ["cache-1"], source: "floriday_connections_cache" });
|
|
22
|
+
});
|
|
23
|
+
it("herkent een ontbrekende functie", () => {
|
|
24
|
+
expect(isMissingFunctionError({ code: "PGRST202" })).toBe(true);
|
|
25
|
+
expect(isMissingFunctionError({ code: "42501", message: "geen toegang" })).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe("belading in de eenvoudige route", () => {
|
|
29
|
+
const full = { vbnPackageCode: "412", piecesPerPackage: "12", packagesPerLayer: "5", layersPerLoadCarrier: "8", loadCarrier: "DANISH_TROLLEY" };
|
|
30
|
+
it("alle vijf velden verplicht, ook lagen per kar en ladingdrager", () => {
|
|
31
|
+
expect(missingPackingFields({ ...full, layersPerLoadCarrier: "" })).toEqual(["lagen per kar"]);
|
|
32
|
+
expect(missingPackingFields({ ...full, loadCarrier: "" })).toEqual(["ladingdrager"]);
|
|
33
|
+
expect(missingPackingFields(full)).toEqual([]);
|
|
34
|
+
});
|
|
35
|
+
it("geen standaardwaarden: onvolledig = fout", () => {
|
|
36
|
+
expect(() => simplePackingToRow({ ...full, piecesPerPackage: "0" })).toThrow(/planten per fust/);
|
|
37
|
+
});
|
|
38
|
+
it("Deense container (DC) gaat als danish_container naar de Engine", () => {
|
|
39
|
+
expect(ENGINE_CARRIER_CODE.DANISH_TROLLEY).toBe("danish_container");
|
|
40
|
+
expect(engineOordeelRegel("p1", full)).toEqual({ product_id: "p1", carrier_code: "danish_container", plants_per_crate: 12, crates_per_layer: 5, layers_per_cart: 8 });
|
|
41
|
+
expect(simplePackingToRow(full)).toMatchObject({ vbn_package_code: 412, pieces_per_package: 12, packages_per_layer: 5, layers_per_load_carrier: 8, is_primary: true });
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-carriers.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/load-carriers.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
vi.mock("../../integrations/supabase/client", () => ({ supabase: {} }));
|
|
3
|
+
import { loadCarriersFromRows } from "../../hooks/useLoadCarriers.js";
|
|
4
|
+
describe("gedeelde lijst ladingdragers", () => {
|
|
5
|
+
it("neemt codes en namen over uit de database, op volgorde", () => {
|
|
6
|
+
const list = loadCarriersFromRows([
|
|
7
|
+
{ code: "DANISH_TROLLEY", naam: "Deense container", volgorde: 2 },
|
|
8
|
+
{ code: "AUCTION_TROLLEY", naam: "Stapelwagen", volgorde: 1 },
|
|
9
|
+
]);
|
|
10
|
+
expect(list.map((c) => c.code)).toEqual(["AUCTION_TROLLEY", "DANISH_TROLLEY"]);
|
|
11
|
+
});
|
|
12
|
+
it("vult niets zelf aan als de database niets geeft", () => {
|
|
13
|
+
expect(loadCarriersFromRows(null)).toEqual([]);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kiest de koperorganisaties voor een aanbod, in vaste volgorde:
|
|
3
|
+
* 1. expliciete keuze, 2. klanten van de prijsgroep(en),
|
|
4
|
+
* 3. Floriday-auth `floriday_buyer_organizations`, 4. alleen als die functie
|
|
5
|
+
* nog niet bestaat: `floriday_connections_cache`.
|
|
6
|
+
*/
|
|
7
|
+
export type BuyerSource = "keuze" | "prijsgroep" | "floriday_buyer_organizations" | "floriday_connections_cache" | "geen";
|
|
8
|
+
export declare const BUYER_SOURCE_LABEL: Record<BuyerSource, string>;
|
|
9
|
+
export interface BuyerInputs {
|
|
10
|
+
explicit: string[];
|
|
11
|
+
priceGroupCustomers: string[];
|
|
12
|
+
/** null = functie bestaat nog niet. */
|
|
13
|
+
authFunction: string[] | null;
|
|
14
|
+
connectionsCache: () => Promise<string[]>;
|
|
15
|
+
}
|
|
16
|
+
export declare function resolveBuyerOrganizations(inp: BuyerInputs): Promise<{
|
|
17
|
+
ids: string[];
|
|
18
|
+
source: BuyerSource;
|
|
19
|
+
tried: BuyerSource[];
|
|
20
|
+
}>;
|
|
21
|
+
/** Fout die aangeeft dat een database-functie (nog) niet bestaat. */
|
|
22
|
+
export declare function isMissingFunctionError(err: {
|
|
23
|
+
code?: string;
|
|
24
|
+
message?: string;
|
|
25
|
+
} | null | undefined): boolean;
|
|
26
|
+
//# sourceMappingURL=buyer-organizations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buyer-organizations.d.ts","sourceRoot":"","sources":["../../src/lib/buyer-organizations.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GACnB,OAAO,GACP,YAAY,GACZ,8BAA8B,GAC9B,4BAA4B,GAC5B,MAAM,CAAC;AAEX,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAM1D,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,uCAAuC;IACvC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC3C;AAWD,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,WAAW,GACf,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,WAAW,EAAE,CAAA;CAAE,CAAC,CAgBvE;AAED,qEAAqE;AACrE,wBAAgB,sBAAsB,CAAC,GAAG,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAG3G"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export const BUYER_SOURCE_LABEL = {
|
|
2
|
+
keuze: "gekozen klanten",
|
|
3
|
+
prijsgroep: "klanten van de prijsgroep",
|
|
4
|
+
floriday_buyer_organizations: "kopers volgens Floriday-koppeling",
|
|
5
|
+
floriday_connections_cache: "koppelingen in Floriday (oude bron)",
|
|
6
|
+
geen: "geen bron",
|
|
7
|
+
};
|
|
8
|
+
function uniq(ids) {
|
|
9
|
+
const out = [];
|
|
10
|
+
for (const raw of ids) {
|
|
11
|
+
const id = typeof raw === "string" ? raw.trim() : "";
|
|
12
|
+
if (id && !out.includes(id))
|
|
13
|
+
out.push(id);
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
export async function resolveBuyerOrganizations(inp) {
|
|
18
|
+
const tried = [];
|
|
19
|
+
const explicit = uniq(inp.explicit);
|
|
20
|
+
tried.push("keuze");
|
|
21
|
+
if (explicit.length)
|
|
22
|
+
return { ids: explicit, source: "keuze", tried };
|
|
23
|
+
const pg = uniq(inp.priceGroupCustomers);
|
|
24
|
+
tried.push("prijsgroep");
|
|
25
|
+
if (pg.length)
|
|
26
|
+
return { ids: pg, source: "prijsgroep", tried };
|
|
27
|
+
if (inp.authFunction !== null) {
|
|
28
|
+
tried.push("floriday_buyer_organizations");
|
|
29
|
+
const a = uniq(inp.authFunction);
|
|
30
|
+
return { ids: a, source: a.length ? "floriday_buyer_organizations" : "geen", tried };
|
|
31
|
+
}
|
|
32
|
+
tried.push("floriday_connections_cache");
|
|
33
|
+
const c = uniq(await inp.connectionsCache());
|
|
34
|
+
return { ids: c, source: c.length ? "floriday_connections_cache" : "geen", tried };
|
|
35
|
+
}
|
|
36
|
+
/** Fout die aangeeft dat een database-functie (nog) niet bestaat. */
|
|
37
|
+
export function isMissingFunctionError(err) {
|
|
38
|
+
if (!err)
|
|
39
|
+
return false;
|
|
40
|
+
return err.code === "PGRST202" || err.code === "42883" || /could not find the function|does not exist/i.test(err.message ?? "");
|
|
41
|
+
}
|
|
@@ -10,6 +10,7 @@ export declare const CustomerOfferInputSchema: z.ZodObject<{
|
|
|
10
10
|
despatchWarehouseId: z.ZodString;
|
|
11
11
|
numberOfPieces: z.ZodNumber;
|
|
12
12
|
allowedCustomerOrganizationIds: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
13
|
+
priceGroupIds: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
13
14
|
packingConfiguration: z.ZodObject<{
|
|
14
15
|
piecesPerPackage: z.ZodNumber;
|
|
15
16
|
vbnPackageCode: z.ZodNumber;
|
|
@@ -41,6 +42,7 @@ export declare const publishCustomerOfferFn: import("@tanstack/start-client-core
|
|
|
41
42
|
despatchWarehouseId: string;
|
|
42
43
|
numberOfPieces: number;
|
|
43
44
|
allowedCustomerOrganizationIds: string[];
|
|
45
|
+
priceGroupIds: string[];
|
|
44
46
|
packingConfiguration: {
|
|
45
47
|
piecesPerPackage: number;
|
|
46
48
|
vbnPackageCode: number;
|
|
@@ -59,5 +61,7 @@ export declare const publishCustomerOfferFn: import("@tanstack/start-client-core
|
|
|
59
61
|
customerOfferLineId: `${string}-${string}-${string}-${string}-${string}`;
|
|
60
62
|
attemptId: string;
|
|
61
63
|
status: number;
|
|
64
|
+
buyerSource: import("./buyer-organizations.js").BuyerSource;
|
|
65
|
+
buyerCount: number;
|
|
62
66
|
}>>;
|
|
63
67
|
//# sourceMappingURL=floriday-customer-offer.functions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floriday-customer-offer.functions.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-customer-offer.functions.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,wBAAwB
|
|
1
|
+
{"version":3,"file":"floriday-customer-offer.functions.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-customer-offer.functions.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;iBA0CnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAyB1E;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;0CAEb,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0LrC,CAAC"}
|
|
@@ -40,6 +40,8 @@ export const CustomerOfferInputSchema = z.object({
|
|
|
40
40
|
* uit `floriday_connections_cache`).
|
|
41
41
|
*/
|
|
42
42
|
allowedCustomerOrganizationIds: z.array(z.string().uuid()).default([]),
|
|
43
|
+
/** Prijsgroepen met een prijs; hun klanten zijn de tweede bron van kopers. */
|
|
44
|
+
priceGroupIds: z.array(z.string()).default([]),
|
|
43
45
|
/**
|
|
44
46
|
* Primaire packing meesturen zodat Floriday de regel goed valideert.
|
|
45
47
|
*/
|
|
@@ -90,26 +92,60 @@ export const publishCustomerOfferFn = createServerFn({ method: "POST" })
|
|
|
90
92
|
const { gatewayWrite } = await import("./floriday-gateway.server.js");
|
|
91
93
|
const activeConnection = await resolveActiveFloridayConnection(context.supabase);
|
|
92
94
|
const environment = activeConnection.environment;
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
95
|
+
// Kopers in vaste volgorde: keuze → prijsgroep → Floriday-auth → oude cache.
|
|
96
|
+
const { resolveBuyerOrganizations, isMissingFunctionError, BUYER_SOURCE_LABEL } = await import("./buyer-organizations.js");
|
|
97
|
+
// Floriday-auth 1.0.126: organization_id, organization_name, gln, sources,
|
|
98
|
+
// in_connections, in_trade_settings, price_group_ids. Match alleen op
|
|
99
|
+
// organization_id; lege lijst = nog geen kopers bekend (nooit aanvullen).
|
|
100
|
+
const { data: authRows, error: authErr } = await context.supabase.rpc("floriday_buyer_organizations", { p_connection_id: activeConnection.id });
|
|
101
|
+
if (authErr && !isMissingFunctionError(authErr)) {
|
|
102
|
+
throw new Error(`Kopers konden niet worden gelezen: ${authErr.message}`);
|
|
103
|
+
}
|
|
104
|
+
const authAvailable = !authErr;
|
|
105
|
+
const authList = (authRows ?? []).filter((r) => r?.organization_id);
|
|
106
|
+
const pgCustomers = [];
|
|
107
|
+
if (data.priceGroupIds.length) {
|
|
108
|
+
if (authAvailable) {
|
|
109
|
+
for (const r of authList) {
|
|
110
|
+
const pgs = Array.isArray(r.price_group_ids) ? r.price_group_ids : [];
|
|
111
|
+
if (pgs.some((p) => data.priceGroupIds.includes(String(p))))
|
|
112
|
+
pgCustomers.push(String(r.organization_id));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const { data: pgRows } = await context.supabase
|
|
117
|
+
.from("floriday_price_groups_cache")
|
|
118
|
+
.select("floriday_id,data")
|
|
119
|
+
.eq("connection_id", activeConnection.id)
|
|
120
|
+
.eq("is_deleted", false)
|
|
121
|
+
.in("floriday_id", data.priceGroupIds);
|
|
122
|
+
for (const r of pgRows ?? []) {
|
|
123
|
+
const list = r?.data?.customers;
|
|
124
|
+
if (Array.isArray(list))
|
|
125
|
+
for (const c of list)
|
|
126
|
+
pgCustomers.push(String(c));
|
|
108
127
|
}
|
|
109
128
|
}
|
|
110
129
|
}
|
|
130
|
+
const authIds = authAvailable ? authList.map((r) => String(r.organization_id)) : null;
|
|
131
|
+
const buyers = await resolveBuyerOrganizations({
|
|
132
|
+
explicit: data.allowedCustomerOrganizationIds,
|
|
133
|
+
priceGroupCustomers: pgCustomers,
|
|
134
|
+
authFunction: authIds,
|
|
135
|
+
connectionsCache: async () => {
|
|
136
|
+
const { data: rows } = await context.supabase
|
|
137
|
+
.from("floriday_connections_cache")
|
|
138
|
+
.select("buyer_organization_id")
|
|
139
|
+
.eq("connection_id", activeConnection.id)
|
|
140
|
+
.eq("is_deleted", false);
|
|
141
|
+
return (rows ?? []).map((r) => r?.buyer_organization_id);
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
const allowed = buyers.ids;
|
|
111
145
|
if (allowed.length === 0) {
|
|
112
|
-
throw new Error(
|
|
146
|
+
throw new Error(`Geen koperorganisaties gevonden. Gezocht in: ${buyers.tried
|
|
147
|
+
.map((s) => BUYER_SOURCE_LABEL[s])
|
|
148
|
+
.join(", ")}. Koppel klanten in Floriday of zet klanten in de prijsgroep.`);
|
|
113
149
|
}
|
|
114
150
|
const orderStart = data.orderStart ?? new Date().toISOString();
|
|
115
151
|
const orderEnd = data.orderEnd ?? addYears(orderStart, 1);
|
|
@@ -211,5 +247,7 @@ export const publishCustomerOfferFn = createServerFn({ method: "POST" })
|
|
|
211
247
|
customerOfferLineId,
|
|
212
248
|
attemptId: res.attemptId,
|
|
213
249
|
status: res.status,
|
|
250
|
+
buyerSource: buyers.source,
|
|
251
|
+
buyerCount: allowed.length,
|
|
214
252
|
};
|
|
215
253
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floriday-info.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-info.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,qBAAqB,EAAE,qBAAqB,EAAE,CAAC;IAC/C,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,GAAG,EAAE,OAAO,CAAC;CACd;AAaD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CA0GvE
|
|
1
|
+
{"version":3,"file":"floriday-info.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-info.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,qBAAqB,EAAE,qBAAqB,EAAE,CAAC;IAC/C,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,GAAG,EAAE,OAAO,CAAC;CACd;AAaD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CA0GvE"}
|
|
@@ -104,11 +104,3 @@ export function floridayInfoFromCache(raw) {
|
|
|
104
104
|
raw,
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
|
-
export const LOAD_CARRIER_LABELS = {
|
|
108
|
-
AUCTION_TROLLEY: "Stapelwagen",
|
|
109
|
-
DANISH_TROLLEY: "Deense container",
|
|
110
|
-
EURO_TROLLEY: "Euro-rolcontainer",
|
|
111
|
-
PALLET: "Pallet",
|
|
112
|
-
EURO_PALLET: "Euro-pallet",
|
|
113
|
-
NONE: "Geen ladingdrager",
|
|
114
|
-
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Belading in de eenvoudige "Artikel toevoegen"-route. Alle vijf velden zijn
|
|
3
|
+
* verplicht (fust, planten per fust, fusten per laag, lagen per kar,
|
|
4
|
+
* ladingdrager); zonder die vijf kan de Engine geen kar plannen.
|
|
5
|
+
* Er worden nooit standaardwaarden ingevuld.
|
|
6
|
+
*/
|
|
7
|
+
import type { ProductPackingRow } from "./product-packings.js";
|
|
8
|
+
export interface SimplePacking {
|
|
9
|
+
vbnPackageCode: string;
|
|
10
|
+
piecesPerPackage: string;
|
|
11
|
+
packagesPerLayer: string;
|
|
12
|
+
layersPerLoadCarrier: string;
|
|
13
|
+
/** Floriday-ladingdrager, bv. DANISH_TROLLEY (DC). */
|
|
14
|
+
loadCarrier: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const EMPTY_SIMPLE_PACKING: SimplePacking;
|
|
17
|
+
/** Floriday-ladingdrager → code van de Engine (load_carrier_types.code). */
|
|
18
|
+
export declare const ENGINE_CARRIER_CODE: Record<string, string>;
|
|
19
|
+
/** Namen van de velden die nog ontbreken of ongeldig zijn (leeg = compleet). */
|
|
20
|
+
export declare function missingPackingFields(p: SimplePacking): string[];
|
|
21
|
+
/** Hoofdverpakking voor product_packings; gooit als iets ontbreekt. */
|
|
22
|
+
export declare function simplePackingToRow(p: SimplePacking): ProductPackingRow;
|
|
23
|
+
/** Regel voor logistics_product_oordeel_belading (Engine). */
|
|
24
|
+
export declare function engineOordeelRegel(productId: string, p: SimplePacking): {
|
|
25
|
+
product_id: string;
|
|
26
|
+
carrier_code: string;
|
|
27
|
+
plants_per_crate: number | null;
|
|
28
|
+
crates_per_layer: number | null;
|
|
29
|
+
layers_per_cart: number | null;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=simple-packing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simple-packing.d.ts","sourceRoot":"","sources":["../../src/lib/simple-packing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,oBAAoB,EAAE,aAMlC,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOtD,CAAC;AAOF,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,EAAE,CAQ/D;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,aAAa,GAAG,iBAAiB,CActE;AAED,8DAA8D;AAC9D,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,aAAa;;;;;;EAQrE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export const EMPTY_SIMPLE_PACKING = {
|
|
2
|
+
vbnPackageCode: "",
|
|
3
|
+
piecesPerPackage: "",
|
|
4
|
+
packagesPerLayer: "",
|
|
5
|
+
layersPerLoadCarrier: "",
|
|
6
|
+
loadCarrier: "",
|
|
7
|
+
};
|
|
8
|
+
/** Floriday-ladingdrager → code van de Engine (load_carrier_types.code). */
|
|
9
|
+
export const ENGINE_CARRIER_CODE = {
|
|
10
|
+
AUCTION_TROLLEY: "trolley",
|
|
11
|
+
DANISH_TROLLEY: "danish_container",
|
|
12
|
+
EURO_TROLLEY: "euro_rolcontainer",
|
|
13
|
+
PALLET: "pallet",
|
|
14
|
+
EURO_PALLET: "euro_pallet",
|
|
15
|
+
NONE: "loose",
|
|
16
|
+
};
|
|
17
|
+
function posInt(v) {
|
|
18
|
+
const n = Number(String(v).trim());
|
|
19
|
+
return Number.isInteger(n) && n > 0 ? n : null;
|
|
20
|
+
}
|
|
21
|
+
/** Namen van de velden die nog ontbreken of ongeldig zijn (leeg = compleet). */
|
|
22
|
+
export function missingPackingFields(p) {
|
|
23
|
+
const out = [];
|
|
24
|
+
if (posInt(p.vbnPackageCode) === null)
|
|
25
|
+
out.push("fust");
|
|
26
|
+
if (posInt(p.piecesPerPackage) === null)
|
|
27
|
+
out.push("planten per fust");
|
|
28
|
+
if (posInt(p.packagesPerLayer) === null)
|
|
29
|
+
out.push("fusten per laag");
|
|
30
|
+
if (posInt(p.layersPerLoadCarrier) === null)
|
|
31
|
+
out.push("lagen per kar");
|
|
32
|
+
if (!ENGINE_CARRIER_CODE[p.loadCarrier])
|
|
33
|
+
out.push("ladingdrager");
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
/** Hoofdverpakking voor product_packings; gooit als iets ontbreekt. */
|
|
37
|
+
export function simplePackingToRow(p) {
|
|
38
|
+
const missing = missingPackingFields(p);
|
|
39
|
+
if (missing.length)
|
|
40
|
+
throw new Error(`Belading onvolledig: ${missing.join(", ")} ontbreekt.`);
|
|
41
|
+
return {
|
|
42
|
+
floriday_packing_id: null,
|
|
43
|
+
vbn_package_code: posInt(p.vbnPackageCode),
|
|
44
|
+
custom_package_id: null,
|
|
45
|
+
load_carrier: p.loadCarrier,
|
|
46
|
+
pieces_per_package: posInt(p.piecesPerPackage),
|
|
47
|
+
packages_per_layer: posInt(p.packagesPerLayer),
|
|
48
|
+
layers_per_load_carrier: posInt(p.layersPerLoadCarrier),
|
|
49
|
+
is_primary: true,
|
|
50
|
+
customer_organization_ids: [],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/** Regel voor logistics_product_oordeel_belading (Engine). */
|
|
54
|
+
export function engineOordeelRegel(productId, p) {
|
|
55
|
+
return {
|
|
56
|
+
product_id: productId,
|
|
57
|
+
carrier_code: ENGINE_CARRIER_CODE[p.loadCarrier] ?? null,
|
|
58
|
+
plants_per_crate: posInt(p.piecesPerPackage),
|
|
59
|
+
crates_per_layer: posInt(p.packagesPerLayer),
|
|
60
|
+
layers_per_cart: posInt(p.layersPerLoadCarrier),
|
|
61
|
+
};
|
|
62
|
+
}
|
package/package.json
CHANGED
package/sql/AGENTS.md
CHANGED
|
@@ -2,4 +2,5 @@
|
|
|
2
2
|
- Voorraad never creates or replaces functions owned by other modules (Engine `logistics_*`, Floriday-auth, Verkoop; list in `FOREIGN_FUNCS` of `scripts/generate-voorraad-schema.py`); the schema file contains own objects only, because the schema sync would overwrite another module's version.
|
|
3
3
|
- Data corrections only via `voorraad_correctie_<nr>(p_uitvoeren default false)` functions: server-only, match on id, insert/update only (never DELETE), hash-check Floriday cache + queue, log every run in `voorraad_correcties`; `voorraad_correctie_status()` tells other modules whether it ran, because loose SQL per Shell is not repeatable.
|
|
4
4
|
- Fust rows are resolved only via `voorraad_active_fust_id(key, id)` (follows `merged_into`), and an order line books fust once: the ERP line adopts an earlier Floriday-ingest booking and ingest skips lines the ERP already booked, because `fust_key LIMIT 1` hit merged rows and both paths booked the same order.
|
|
5
|
-
- An order line
|
|
5
|
+
- An order line counts as cancelled for fust when `order_items.quarantined_at` is set or its order is cancelled (`voorraad_order_geannuleerd`: status geannuleerd/cancelled case-insensitive, `cancelled_at` or `deleted_at`): `sync_order_item_fusten` wants 0 and triggers on order_items (quarantine on/off) and orders (those three fields) book the difference against the line's own bookings, because quarantined or cancelled orders otherwise kept fust booked.
|
|
6
|
+
- The correct fust count per order line comes only from `voorraad_fust_juist(order_item_id)` (same rule as `sync_order_item_fusten`; removed, quarantined, externally fulfilled or cancelled = 0); fust corrections compare against it, because every hand-built copy of the rule drifted.
|