@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.
- package/dist-lib/components/voorraad/ArtikelWizard.d.ts +2 -1
- package/dist-lib/components/voorraad/ArtikelWizard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/ArtikelWizard.js +576 -324
- package/dist-lib/components/voorraad/EditArtikelPage.d.ts +2 -1
- package/dist-lib/components/voorraad/EditArtikelPage.d.ts.map +1 -1
- package/dist-lib/components/voorraad/EditArtikelPage.js +5 -4
- package/dist-lib/components/voorraad/FustenPage.d.ts +2 -0
- package/dist-lib/components/voorraad/FustenPage.d.ts.map +1 -0
- package/dist-lib/components/voorraad/FustenPage.js +97 -0
- package/dist-lib/components/voorraad/LogistiekTakenCard.d.ts +2 -0
- package/dist-lib/components/voorraad/LogistiekTakenCard.d.ts.map +1 -0
- package/dist-lib/components/voorraad/LogistiekTakenCard.js +54 -0
- package/dist-lib/components/voorraad/ProductCustomFieldsCard.d.ts +5 -0
- package/dist-lib/components/voorraad/ProductCustomFieldsCard.d.ts.map +1 -0
- package/dist-lib/components/voorraad/ProductCustomFieldsCard.js +65 -0
- package/dist-lib/components/voorraad/PublicatiesPage.d.ts +2 -0
- package/dist-lib/components/voorraad/PublicatiesPage.d.ts.map +1 -0
- package/dist-lib/components/voorraad/PublicatiesPage.js +60 -0
- package/dist-lib/components/voorraad/PublishProgressCard.d.ts +12 -0
- package/dist-lib/components/voorraad/PublishProgressCard.d.ts.map +1 -0
- package/dist-lib/components/voorraad/PublishProgressCard.js +30 -0
- package/dist-lib/components/voorraad/PublishReadinessCard.d.ts +10 -0
- package/dist-lib/components/voorraad/PublishReadinessCard.d.ts.map +1 -0
- package/dist-lib/components/voorraad/PublishReadinessCard.js +12 -0
- package/dist-lib/components/voorraad/StockBulkButtons.d.ts.map +1 -1
- package/dist-lib/components/voorraad/StockBulkButtons.js +65 -2
- package/dist-lib/components/voorraad/StockSyncStatus.d.ts +2 -0
- package/dist-lib/components/voorraad/StockSyncStatus.d.ts.map +1 -0
- package/dist-lib/components/voorraad/StockSyncStatus.js +23 -0
- package/dist-lib/components/voorraad/ValidationOverviewTable.d.ts.map +1 -1
- package/dist-lib/components/voorraad/ValidationOverviewTable.js +8 -2
- package/dist-lib/components/voorraad/VoorraadDashboard.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadDashboard.js +4 -1
- package/dist-lib/components/voorraad/VoorraadPage.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadPage.js +5 -1
- package/dist-lib/components/voorraad/VoorraadTable.d.ts.map +1 -1
- package/dist-lib/components/voorraad/VoorraadTable.js +10 -2
- package/dist-lib/components/voorraad/VoorraadVeldenCard.d.ts +2 -0
- package/dist-lib/components/voorraad/VoorraadVeldenCard.d.ts.map +1 -0
- package/dist-lib/components/voorraad/VoorraadVeldenCard.js +97 -0
- package/dist-lib/hooks/useFusten.d.ts +17 -0
- package/dist-lib/hooks/useFusten.d.ts.map +1 -0
- package/dist-lib/hooks/useFusten.js +81 -0
- package/dist-lib/hooks/useLocalTradeItems.d.ts +17 -7
- package/dist-lib/hooks/useLocalTradeItems.d.ts.map +1 -1
- package/dist-lib/hooks/useLocalTradeItems.js +139 -37
- package/dist-lib/hooks/useLogisticsTasks.d.ts +13 -0
- package/dist-lib/hooks/useLogisticsTasks.d.ts.map +1 -0
- package/dist-lib/hooks/useLogisticsTasks.js +155 -0
- package/dist-lib/hooks/usePublishJob.d.ts +13 -0
- package/dist-lib/hooks/usePublishJob.d.ts.map +1 -0
- package/dist-lib/hooks/usePublishJob.js +67 -0
- package/dist-lib/hooks/useRegisterModuleBaseUrl.d.ts +2 -0
- package/dist-lib/hooks/useRegisterModuleBaseUrl.d.ts.map +1 -0
- package/dist-lib/hooks/useRegisterModuleBaseUrl.js +31 -0
- package/dist-lib/hooks/useStockSyncHealth.d.ts +8 -0
- package/dist-lib/hooks/useStockSyncHealth.d.ts.map +1 -0
- package/dist-lib/hooks/useStockSyncHealth.js +42 -0
- package/dist-lib/hooks/useTradeItemStock.d.ts.map +1 -1
- package/dist-lib/hooks/useTradeItemStock.js +37 -1
- package/dist-lib/hooks/useVoorraadCustomFields.d.ts +9 -0
- package/dist-lib/hooks/useVoorraadCustomFields.d.ts.map +1 -0
- package/dist-lib/hooks/useVoorraadCustomFields.js +26 -0
- package/dist-lib/index.d.ts +2 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +9 -2
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +8467 -4487
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +8467 -4487
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +8467 -4487
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +8714 -4631
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +49 -0
- package/dist-lib/lib/floricode-required-features.functions.d.ts +8467 -4487
- package/dist-lib/lib/floricode-required-features.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-client.d.ts +1 -1
- package/dist-lib/lib/floriday-client.d.ts.map +1 -1
- package/dist-lib/lib/floriday-client.js +1 -2
- package/dist-lib/lib/floriday-customer-offer.functions.d.ts +8467 -4487
- package/dist-lib/lib/floriday-customer-offer.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-customer-offer.functions.js +14 -19
- package/dist-lib/lib/floriday-env.functions.d.ts +35712 -0
- package/dist-lib/lib/floriday-env.functions.d.ts.map +1 -0
- package/dist-lib/lib/floriday-env.functions.js +16 -0
- package/dist-lib/lib/floriday-env.server.d.ts +12 -0
- package/dist-lib/lib/floriday-env.server.d.ts.map +1 -1
- package/dist-lib/lib/floriday-env.server.js +15 -2
- package/dist-lib/lib/floriday-gateway.functions.d.ts +77902 -40145
- package/dist-lib/lib/floriday-gateway.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-gateway.functions.js +12 -3
- package/dist-lib/lib/floriday-readiness.server.d.ts +11 -0
- package/dist-lib/lib/floriday-readiness.server.d.ts.map +1 -0
- package/dist-lib/lib/floriday-readiness.server.js +43 -0
- package/dist-lib/lib/floriday-vbn-required.functions.d.ts +23115 -15155
- package/dist-lib/lib/floriday-vbn-required.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-warehouse.functions.d.ts +31362 -19422
- package/dist-lib/lib/floriday-warehouse.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-warehouse.functions.js +3 -0
- package/dist-lib/lib/floriday-writes.functions.d.ts +23191 -15231
- package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -1
- package/dist-lib/lib/fusten.d.ts +87 -0
- package/dist-lib/lib/fusten.d.ts.map +1 -0
- package/dist-lib/lib/fusten.js +389 -0
- package/dist-lib/lib/logistics-engine.d.ts +63 -0
- package/dist-lib/lib/logistics-engine.d.ts.map +1 -0
- package/dist-lib/lib/logistics-engine.js +57 -0
- package/dist-lib/lib/logistics-events.d.ts +18 -0
- package/dist-lib/lib/logistics-events.d.ts.map +1 -0
- package/dist-lib/lib/logistics-events.js +61 -0
- package/dist-lib/lib/module-runtime-config.functions.d.ts +14 -0
- package/dist-lib/lib/module-runtime-config.functions.d.ts.map +1 -0
- package/dist-lib/lib/module-runtime-config.functions.js +107 -0
- package/dist-lib/lib/publish-errors.d.ts +37 -0
- package/dist-lib/lib/publish-errors.d.ts.map +1 -0
- package/dist-lib/lib/publish-errors.js +183 -0
- package/dist-lib/lib/publish-pipeline.d.ts +91 -0
- package/dist-lib/lib/publish-pipeline.d.ts.map +1 -0
- package/dist-lib/lib/publish-pipeline.js +212 -0
- package/dist-lib/lib/publish-readiness.d.ts +42 -0
- package/dist-lib/lib/publish-readiness.d.ts.map +1 -0
- package/dist-lib/lib/publish-readiness.js +102 -0
- package/dist-lib/lib/voorraad-custom-fields.d.ts +22 -0
- package/dist-lib/lib/voorraad-custom-fields.d.ts.map +1 -0
- package/dist-lib/lib/voorraad-custom-fields.js +71 -0
- package/package.json +2 -2
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { useCallback, useEffect, useState } from "react";
|
|
2
2
|
import { supabase } from "../integrations/supabase/client";
|
|
3
3
|
import { derivePrimaryPacking } from "../lib/floriday-client";
|
|
4
|
+
function asRecord(value) {
|
|
5
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
6
|
+
? value
|
|
7
|
+
: {};
|
|
8
|
+
}
|
|
4
9
|
function productToTradeItem(row) {
|
|
5
|
-
const
|
|
10
|
+
const cf = asRecord(row.custom_fields);
|
|
11
|
+
const payload = asRecord(cf.floriday_payload);
|
|
12
|
+
const floridayId = row.floriday_trade_item_id ||
|
|
13
|
+
(typeof cf.floriday_id === "string" ? cf.floriday_id : null) ||
|
|
14
|
+
(row.trade_item_key && !row.trade_item_key.startsWith("product:")
|
|
15
|
+
? row.trade_item_key
|
|
16
|
+
: null);
|
|
6
17
|
const firstImage = Array.isArray(payload.images) && payload.images.length > 0 ? payload.images[0] : null;
|
|
7
18
|
const payloadImage = (firstImage && (firstImage.url || firstImage.previewUrl)) ?? null;
|
|
8
19
|
const packingConfigurations = Array.isArray(payload.packingConfigurations)
|
|
@@ -14,7 +25,7 @@ function productToTradeItem(row) {
|
|
|
14
25
|
id: row.id,
|
|
15
26
|
productId: row.id,
|
|
16
27
|
localId: row.id,
|
|
17
|
-
tradeItemKey: `product:${row.id}`,
|
|
28
|
+
tradeItemKey: row.trade_item_key || `product:${row.id}`,
|
|
18
29
|
source: "product",
|
|
19
30
|
name,
|
|
20
31
|
articleNumber,
|
|
@@ -26,18 +37,18 @@ function productToTradeItem(row) {
|
|
|
26
37
|
incomingQuantity: 0,
|
|
27
38
|
economicQuantity: 0,
|
|
28
39
|
raw: row,
|
|
29
|
-
floridayActive:
|
|
30
|
-
published:
|
|
31
|
-
linkStatus:
|
|
40
|
+
floridayActive: Boolean(floridayId),
|
|
41
|
+
published: Boolean(floridayId),
|
|
42
|
+
linkStatus: floridayId ? "published" : "linked",
|
|
32
43
|
missingFields: [],
|
|
33
44
|
linkError: null,
|
|
34
45
|
lastSyncAt: null,
|
|
35
|
-
floridayId
|
|
46
|
+
floridayId,
|
|
36
47
|
packingConfigurations,
|
|
37
48
|
primaryPacking: derivePrimaryPacking(packingConfigurations),
|
|
38
49
|
};
|
|
39
50
|
}
|
|
40
|
-
const SELECT_COLS = "id,product,article_number,barcode,image_url,
|
|
51
|
+
const SELECT_COLS = "id,product,article_number,barcode,image_url,trade_item_key,floriday_trade_item_id,custom_fields,updated_at,created_at";
|
|
41
52
|
/**
|
|
42
53
|
* `connectionId` wordt vandaag genegeerd: producten zijn niet meer per Floriday-connectie gescoped.
|
|
43
54
|
* De parameter blijft in de signatuur zodat bestaande callers zonder wijziging werken.
|
|
@@ -83,21 +94,54 @@ export async function getLocalTradeItem(id) {
|
|
|
83
94
|
return {
|
|
84
95
|
id: p.id,
|
|
85
96
|
connection_id: null,
|
|
86
|
-
data: (p.floriday_payload ?? {
|
|
97
|
+
data: (asRecord(p.custom_fields).floriday_payload ?? {
|
|
98
|
+
...{},
|
|
99
|
+
name: p.product ?? "",
|
|
100
|
+
articleCode: p.article_number ?? "",
|
|
101
|
+
gtin: p.barcode ?? "",
|
|
102
|
+
}),
|
|
87
103
|
updated_at: p.updated_at,
|
|
88
104
|
created_at: p.created_at,
|
|
89
|
-
floriday_id: p.floriday_trade_item_id,
|
|
90
|
-
floriday_link_status: p.
|
|
105
|
+
floriday_id: p.floriday_trade_item_id ?? asRecord(p.custom_fields).floriday_id ?? null,
|
|
106
|
+
floriday_link_status: p.floriday_trade_item_id || asRecord(p.custom_fields).floriday_id ? "published" : "linked",
|
|
91
107
|
missing_required_fields: [],
|
|
92
108
|
last_floriday_sync_at: null,
|
|
93
109
|
floriday_link_error: null,
|
|
94
110
|
source: "product",
|
|
95
111
|
};
|
|
96
112
|
}
|
|
113
|
+
export function readLocalSyncStatus(customFields) {
|
|
114
|
+
const cf = asRecord(customFields);
|
|
115
|
+
const raw = cf.floriday_sync;
|
|
116
|
+
if (!raw || typeof raw !== "object")
|
|
117
|
+
return null;
|
|
118
|
+
const s = raw;
|
|
119
|
+
return {
|
|
120
|
+
dirty: Boolean(s.dirty),
|
|
121
|
+
last_attempt_at: s.last_attempt_at ?? null,
|
|
122
|
+
last_error: s.last_error ?? null,
|
|
123
|
+
last_synced_at: s.last_synced_at ?? null,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
97
126
|
/**
|
|
98
|
-
* Slaat Floriday-velden op in `products.floriday_payload`. Als `id` ontbreekt maken we een
|
|
127
|
+
* Slaat Floriday-velden op in `products.custom_fields.floriday_payload`. Als `id` ontbreekt maken we een
|
|
99
128
|
* nieuw product aan (met minimale ERP-velden uit de payload). Nooit een concept-rij.
|
|
129
|
+
*
|
|
130
|
+
* `sync` legt vast of de gegevens al door Floriday zijn bevestigd. Zolang `dirty` waar is,
|
|
131
|
+
* is de lokale payload leidend bij het opnieuw openen van het artikel.
|
|
100
132
|
*/
|
|
133
|
+
/** Nieuw fusttype in een belading meteen in de fustenvoorraad registreren. */
|
|
134
|
+
function scheduleFustSync(connectionId) {
|
|
135
|
+
void (async () => {
|
|
136
|
+
try {
|
|
137
|
+
const { syncFustTypes } = await import("../lib/fusten");
|
|
138
|
+
await syncFustTypes(connectionId);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Fustenvoorraad is secundair; nooit het opslaan blokkeren.
|
|
142
|
+
}
|
|
143
|
+
})();
|
|
144
|
+
}
|
|
101
145
|
export async function upsertLocalTradeItem(params) {
|
|
102
146
|
const userRes = await supabase.auth.getUser();
|
|
103
147
|
const userId = userRes.data.user?.id;
|
|
@@ -107,16 +151,34 @@ export async function upsertLocalTradeItem(params) {
|
|
|
107
151
|
const linkedProductId = typeof payload.linkedProductId === "string" && payload.linkedProductId
|
|
108
152
|
? String(payload.linkedProductId)
|
|
109
153
|
: null;
|
|
110
|
-
|
|
154
|
+
let targetId = params.id && params.id.length > 0 ? params.id : linkedProductId;
|
|
155
|
+
// Bestaat er al een lokale rij voor dit Floriday-artikel? Dan daarop schrijven
|
|
156
|
+
// in plaats van een duplicaat aanmaken.
|
|
157
|
+
const floridayTradeItemId = params.floridayTradeItemId ?? params.meta?.floridayId ?? null;
|
|
158
|
+
if (!targetId && floridayTradeItemId) {
|
|
159
|
+
const { data: byFloriday } = await supabase
|
|
160
|
+
.from("products")
|
|
161
|
+
.select("id")
|
|
162
|
+
.eq("floriday_trade_item_id", floridayTradeItemId)
|
|
163
|
+
.maybeSingle();
|
|
164
|
+
targetId = byFloriday?.id ?? null;
|
|
165
|
+
}
|
|
166
|
+
const syncPatch = params.sync
|
|
167
|
+
? {
|
|
168
|
+
dirty: params.sync.dirty,
|
|
169
|
+
last_attempt_at: params.sync.last_attempt_at ?? new Date().toISOString(),
|
|
170
|
+
last_error: params.sync.last_error ?? null,
|
|
171
|
+
last_synced_at: params.sync.last_synced_at ?? null,
|
|
172
|
+
}
|
|
173
|
+
: null;
|
|
111
174
|
const productPatch = {
|
|
112
|
-
floriday_payload: payload,
|
|
113
175
|
updated_at: new Date().toISOString(),
|
|
114
176
|
};
|
|
115
177
|
if (params.meta?.floridayId !== undefined) {
|
|
116
178
|
productPatch.floriday_trade_item_id = params.meta.floridayId;
|
|
117
179
|
}
|
|
118
|
-
if (
|
|
119
|
-
productPatch.
|
|
180
|
+
else if (floridayTradeItemId) {
|
|
181
|
+
productPatch.floriday_trade_item_id = floridayTradeItemId;
|
|
120
182
|
}
|
|
121
183
|
if (payload.name)
|
|
122
184
|
productPatch.product = payload.name;
|
|
@@ -128,21 +190,29 @@ export async function upsertLocalTradeItem(params) {
|
|
|
128
190
|
const firstImageUrl = firstImage?.url || firstImage?.previewUrl;
|
|
129
191
|
if (firstImageUrl)
|
|
130
192
|
productPatch.image_url = firstImageUrl;
|
|
131
|
-
if (payload.vatRate !== undefined) {
|
|
132
|
-
const v = payload.vatRate;
|
|
133
|
-
productPatch.vat_rate = v === null || v === "" || Number.isNaN(Number(v)) ? null : Number(v);
|
|
134
|
-
}
|
|
135
|
-
if (payload.vatCode !== undefined) {
|
|
136
|
-
const c = payload.vatCode;
|
|
137
|
-
productPatch.vat_code = c && String(c).length > 0 ? String(c) : null;
|
|
138
|
-
}
|
|
139
193
|
if (targetId) {
|
|
194
|
+
const { data: existing } = await supabase
|
|
195
|
+
.from("products")
|
|
196
|
+
.select("custom_fields")
|
|
197
|
+
.eq("id", targetId)
|
|
198
|
+
.maybeSingle();
|
|
199
|
+
const currentCustomFields = asRecord(existing?.custom_fields);
|
|
200
|
+
productPatch.custom_fields = {
|
|
201
|
+
...currentCustomFields,
|
|
202
|
+
articleCode: payload.articleCode || currentCustomFields.articleCode,
|
|
203
|
+
floriday_id: params.meta?.floridayId !== undefined
|
|
204
|
+
? params.meta.floridayId
|
|
205
|
+
: (currentCustomFields.floriday_id ?? floridayTradeItemId ?? null),
|
|
206
|
+
floriday_payload: payload,
|
|
207
|
+
...(syncPatch ? { floriday_sync: syncPatch } : {}),
|
|
208
|
+
};
|
|
140
209
|
const { error } = await supabase
|
|
141
210
|
.from("products")
|
|
142
211
|
.update(productPatch)
|
|
143
212
|
.eq("id", targetId);
|
|
144
213
|
if (error)
|
|
145
214
|
throw new Error(error.message);
|
|
215
|
+
scheduleFustSync(params.connectionId ?? null);
|
|
146
216
|
return targetId;
|
|
147
217
|
}
|
|
148
218
|
const generatedId = crypto.randomUUID();
|
|
@@ -157,33 +227,65 @@ export async function upsertLocalTradeItem(params) {
|
|
|
157
227
|
barcode: payload.gtin || null,
|
|
158
228
|
image_url: firstImageUrl || null,
|
|
159
229
|
product_type: "levend",
|
|
160
|
-
trade_item_key: `product:${generatedId}`,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
:
|
|
167
|
-
|
|
168
|
-
? String(payload.vatCode)
|
|
169
|
-
: null,
|
|
230
|
+
trade_item_key: floridayTradeItemId ?? `product:${generatedId}`,
|
|
231
|
+
floriday_trade_item_id: params.meta?.floridayId ?? floridayTradeItemId ?? null,
|
|
232
|
+
custom_fields: {
|
|
233
|
+
articleCode: payload.articleCode || null,
|
|
234
|
+
floriday_id: params.meta?.floridayId ?? floridayTradeItemId ?? null,
|
|
235
|
+
floriday_payload: payload,
|
|
236
|
+
...(syncPatch ? { floriday_sync: syncPatch } : {}),
|
|
237
|
+
},
|
|
170
238
|
};
|
|
171
239
|
const { error } = await supabase.from("products").insert(insertRow);
|
|
172
240
|
if (error)
|
|
173
241
|
throw new Error(error.message);
|
|
242
|
+
scheduleFustSync(params.connectionId ?? null);
|
|
174
243
|
return generatedId;
|
|
175
244
|
}
|
|
245
|
+
/** Zet alleen de sync-status bij, zonder de payload te herschrijven. */
|
|
246
|
+
export async function markLocalSyncStatus(productRowId, status) {
|
|
247
|
+
const { data } = await supabase
|
|
248
|
+
.from("products")
|
|
249
|
+
.select("custom_fields")
|
|
250
|
+
.eq("id", productRowId)
|
|
251
|
+
.maybeSingle();
|
|
252
|
+
const current = asRecord(data?.custom_fields);
|
|
253
|
+
const next = {
|
|
254
|
+
...current,
|
|
255
|
+
floriday_sync: {
|
|
256
|
+
dirty: status.dirty,
|
|
257
|
+
last_attempt_at: status.last_attempt_at ?? new Date().toISOString(),
|
|
258
|
+
last_error: status.last_error ?? null,
|
|
259
|
+
last_synced_at: status.last_synced_at ?? null,
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
const { error } = await supabase
|
|
263
|
+
.from("products")
|
|
264
|
+
.update({ custom_fields: next })
|
|
265
|
+
.eq("id", productRowId);
|
|
266
|
+
if (error)
|
|
267
|
+
throw new Error(error.message);
|
|
268
|
+
}
|
|
176
269
|
/**
|
|
177
|
-
* Legacy API. Alleen meta-velden die vandaag nog op `products` bestaan (`
|
|
178
|
-
* `
|
|
270
|
+
* Legacy API. Alleen meta-velden die vandaag nog op `products` bestaan (`floriday_trade_item_id`
|
|
271
|
+
* en `custom_fields.floriday_id`) worden gepersisteerd; overige velden worden stilzwijgend genegeerd
|
|
179
272
|
* omdat het draft-model verdwenen is.
|
|
180
273
|
*/
|
|
181
274
|
export async function updateDraftMeta(id, meta) {
|
|
182
275
|
const patch = {};
|
|
183
276
|
if (meta.floridayId !== undefined)
|
|
184
277
|
patch.floriday_trade_item_id = meta.floridayId;
|
|
185
|
-
if (meta.
|
|
186
|
-
|
|
278
|
+
if (meta.floridayId !== undefined) {
|
|
279
|
+
const { data } = await supabase
|
|
280
|
+
.from("products")
|
|
281
|
+
.select("custom_fields")
|
|
282
|
+
.eq("id", id)
|
|
283
|
+
.maybeSingle();
|
|
284
|
+
patch.custom_fields = {
|
|
285
|
+
...asRecord(data?.custom_fields),
|
|
286
|
+
floriday_id: meta.floridayId,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
187
289
|
if (Object.keys(patch).length === 0)
|
|
188
290
|
return;
|
|
189
291
|
const { error } = await supabase.from("products").update(patch).eq("id", id);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type LogisticsTaskRow, type TaskExecutionResult } from "../lib/logistics-engine";
|
|
2
|
+
export declare function useLogisticsTasks(statuses?: string[]): {
|
|
3
|
+
tasks: LogisticsTaskRow[];
|
|
4
|
+
loading: boolean;
|
|
5
|
+
error: string | null;
|
|
6
|
+
refetch: () => Promise<void>;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Voert één `stock.reserve` taak uit. De Engine bepaalt WAT er gereserveerd
|
|
10
|
+
* wordt; deze module rekent niets zelf uit.
|
|
11
|
+
*/
|
|
12
|
+
export declare function runStockReserveTask(task: LogisticsTaskRow, connectionId: string | null): Promise<TaskExecutionResult>;
|
|
13
|
+
//# sourceMappingURL=useLogisticsTasks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLogisticsTasks.d.ts","sourceRoot":"","sources":["../../src/hooks/useLogisticsTasks.ts"],"names":[],"mappings":"AAUA,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACzB,MAAM,yBAAyB,CAAC;AAKjC,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,MAAM,EAAyB;;;;;EAuD1E;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,gBAAgB,EACtB,YAAY,EAAE,MAAM,GAAG,IAAI,GAC1B,OAAO,CAAC,mBAAmB,CAAC,CAoG9B"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Taken van de Logistics Engine voor deze module, rechtstreeks uit de
|
|
3
|
+
* gedeelde Supabase-database (public.logistics_tasks).
|
|
4
|
+
*
|
|
5
|
+
* De Engine plant; wij tonen, voeren `stock.reserve` uit en melden af.
|
|
6
|
+
* In schaduwmodus wordt alleen vergeleken en NIETS geschreven aan voorraad;
|
|
7
|
+
* de taak wordt dan ook niet afgemeld.
|
|
8
|
+
*/
|
|
9
|
+
import { useCallback, useEffect, useState } from "react";
|
|
10
|
+
import { supabase } from "../integrations/supabase/client";
|
|
11
|
+
import { OWNER_MODULE, describeLoadCarriers, parseStockReservePlan, } from "../lib/logistics-engine";
|
|
12
|
+
const TASK_COLUMNS = "id,order_ref,buffer_ref,task_type,sequence,depends_on,planned_start,planned_end,due_at,status,shadow,payload,result,rule_version";
|
|
13
|
+
export function useLogisticsTasks(statuses = ["planned", "ready"]) {
|
|
14
|
+
const key = statuses.join(",");
|
|
15
|
+
const [tasks, setTasks] = useState([]);
|
|
16
|
+
const [loading, setLoading] = useState(true);
|
|
17
|
+
const [error, setError] = useState(null);
|
|
18
|
+
const refetch = useCallback(async () => {
|
|
19
|
+
const { data, error } = await supabase
|
|
20
|
+
.from("logistics_tasks")
|
|
21
|
+
.select(TASK_COLUMNS)
|
|
22
|
+
.eq("owner_module", OWNER_MODULE)
|
|
23
|
+
.in("status", key.split(","))
|
|
24
|
+
.order("planned_start", { ascending: true });
|
|
25
|
+
if (error) {
|
|
26
|
+
setError(error.message);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
setError(null);
|
|
30
|
+
setTasks((data ?? []));
|
|
31
|
+
}, [key]);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
let cancelled = false;
|
|
34
|
+
setLoading(true);
|
|
35
|
+
(async () => {
|
|
36
|
+
await refetch();
|
|
37
|
+
if (!cancelled)
|
|
38
|
+
setLoading(false);
|
|
39
|
+
})();
|
|
40
|
+
return () => {
|
|
41
|
+
cancelled = true;
|
|
42
|
+
};
|
|
43
|
+
}, [refetch]);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const channel = supabase
|
|
46
|
+
.channel(`logistics-tasks-${OWNER_MODULE}`)
|
|
47
|
+
.on("postgres_changes", {
|
|
48
|
+
event: "*",
|
|
49
|
+
schema: "public",
|
|
50
|
+
table: "logistics_tasks",
|
|
51
|
+
filter: `owner_module=eq.${OWNER_MODULE}`,
|
|
52
|
+
}, () => {
|
|
53
|
+
refetch();
|
|
54
|
+
})
|
|
55
|
+
.subscribe();
|
|
56
|
+
return () => {
|
|
57
|
+
supabase.removeChannel(channel);
|
|
58
|
+
};
|
|
59
|
+
}, [refetch]);
|
|
60
|
+
return { tasks, loading, error, refetch };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Voert één `stock.reserve` taak uit. De Engine bepaalt WAT er gereserveerd
|
|
64
|
+
* wordt; deze module rekent niets zelf uit.
|
|
65
|
+
*/
|
|
66
|
+
export async function runStockReserveTask(task, connectionId) {
|
|
67
|
+
const plan = parseStockReservePlan(task.payload);
|
|
68
|
+
const shadow = task.shadow;
|
|
69
|
+
if (plan.lines.length === 0) {
|
|
70
|
+
return {
|
|
71
|
+
taskId: task.id,
|
|
72
|
+
applied: false,
|
|
73
|
+
shadow,
|
|
74
|
+
diff: [],
|
|
75
|
+
message: `Taak zonder regels (${describeLoadCarriers(plan.loadCarriers)}).`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const keys = plan.lines.map((l) => l.tradeItemKey);
|
|
79
|
+
let query = supabase
|
|
80
|
+
.from("trade_item_stock")
|
|
81
|
+
.select("trade_item_key,physical_stock,reserved_stock,connection_id")
|
|
82
|
+
.in("trade_item_key", keys);
|
|
83
|
+
if (connectionId)
|
|
84
|
+
query = query.eq("connection_id", connectionId);
|
|
85
|
+
const { data: rows, error: readError } = await query;
|
|
86
|
+
if (readError)
|
|
87
|
+
throw new Error(`voorraad lezen: ${readError.message}`);
|
|
88
|
+
const stock = (rows ?? []);
|
|
89
|
+
const diff = plan.lines.map((line) => {
|
|
90
|
+
const row = stock.find((r) => r.trade_item_key === line.tradeItemKey);
|
|
91
|
+
const currentReserved = row?.reserved_stock ?? 0;
|
|
92
|
+
return {
|
|
93
|
+
tradeItemKey: line.tradeItemKey,
|
|
94
|
+
currentReserved,
|
|
95
|
+
engineReserved: line.quantity,
|
|
96
|
+
delta: line.quantity - currentReserved,
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
if (shadow) {
|
|
100
|
+
return {
|
|
101
|
+
taskId: task.id,
|
|
102
|
+
applied: false,
|
|
103
|
+
shadow: true,
|
|
104
|
+
diff,
|
|
105
|
+
message: `Schaduwmodus: ${diff.length} regel(s) vergeleken, niets geschreven (${describeLoadCarriers(plan.loadCarriers)}).`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
await supabase
|
|
109
|
+
.from("logistics_tasks")
|
|
110
|
+
.update({ status: "in_progress", started_at: new Date().toISOString() })
|
|
111
|
+
.eq("id", task.id);
|
|
112
|
+
try {
|
|
113
|
+
for (const line of plan.lines) {
|
|
114
|
+
const row = stock.find((r) => r.trade_item_key === line.tradeItemKey);
|
|
115
|
+
if (!row)
|
|
116
|
+
throw new Error(`Geen voorraadrij voor ${line.tradeItemKey}`);
|
|
117
|
+
const { error } = await supabase
|
|
118
|
+
.from("trade_item_stock")
|
|
119
|
+
.update({ reserved_stock: line.quantity })
|
|
120
|
+
.eq("connection_id", row.connection_id)
|
|
121
|
+
.eq("trade_item_key", line.tradeItemKey);
|
|
122
|
+
if (error) {
|
|
123
|
+
throw new Error(`reservering ${line.tradeItemKey}: ${error.message}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
const message = e?.message ?? String(e);
|
|
129
|
+
await supabase
|
|
130
|
+
.from("logistics_tasks")
|
|
131
|
+
.update({
|
|
132
|
+
status: "failed",
|
|
133
|
+
result: { message, diff },
|
|
134
|
+
completed_at: new Date().toISOString(),
|
|
135
|
+
})
|
|
136
|
+
.eq("id", task.id);
|
|
137
|
+
throw new Error(message);
|
|
138
|
+
}
|
|
139
|
+
const result = {
|
|
140
|
+
taskId: task.id,
|
|
141
|
+
applied: true,
|
|
142
|
+
shadow: false,
|
|
143
|
+
diff,
|
|
144
|
+
message: `${plan.lines.length} regel(s) gereserveerd (${describeLoadCarriers(plan.loadCarriers)}).`,
|
|
145
|
+
};
|
|
146
|
+
await supabase
|
|
147
|
+
.from("logistics_tasks")
|
|
148
|
+
.update({
|
|
149
|
+
status: "done",
|
|
150
|
+
result: result,
|
|
151
|
+
completed_at: new Date().toISOString(),
|
|
152
|
+
})
|
|
153
|
+
.eq("id", task.id);
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type PublishJobRow, type PublishStepRow } from "../lib/publish-pipeline";
|
|
2
|
+
export declare function usePublishJob(jobId: string | null): {
|
|
3
|
+
job: PublishJobRow | null;
|
|
4
|
+
steps: PublishStepRow[];
|
|
5
|
+
loading: boolean;
|
|
6
|
+
reload: () => Promise<void>;
|
|
7
|
+
};
|
|
8
|
+
export declare function usePublishJobs(limit?: number): {
|
|
9
|
+
jobs: PublishJobRow[];
|
|
10
|
+
loading: boolean;
|
|
11
|
+
reload: () => Promise<void>;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=usePublishJob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePublishJob.d.ts","sourceRoot":"","sources":["../../src/hooks/usePublishJob.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAEjC,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;;;;;EAqDjD;AAED,wBAAgB,cAAc,CAAC,KAAK,SAAK;;;;EAoBxC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Volgt een lopende publicatie live: opdracht + deelstappen.
|
|
3
|
+
*/
|
|
4
|
+
import { useEffect, useState, useCallback } from "react";
|
|
5
|
+
import { supabase } from "../integrations/supabase/client";
|
|
6
|
+
import { loadPublishJob, } from "../lib/publish-pipeline";
|
|
7
|
+
export function usePublishJob(jobId) {
|
|
8
|
+
const [job, setJob] = useState(null);
|
|
9
|
+
const [steps, setSteps] = useState([]);
|
|
10
|
+
const [loading, setLoading] = useState(false);
|
|
11
|
+
const reload = useCallback(async () => {
|
|
12
|
+
if (!jobId) {
|
|
13
|
+
setJob(null);
|
|
14
|
+
setSteps([]);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
setLoading(true);
|
|
18
|
+
const res = await loadPublishJob(jobId);
|
|
19
|
+
setJob(res.job);
|
|
20
|
+
setSteps(res.steps);
|
|
21
|
+
setLoading(false);
|
|
22
|
+
}, [jobId]);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
void reload();
|
|
25
|
+
}, [reload]);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!jobId)
|
|
28
|
+
return;
|
|
29
|
+
const channel = supabase
|
|
30
|
+
.channel(`publish-job-${jobId}`)
|
|
31
|
+
.on("postgres_changes", {
|
|
32
|
+
event: "*",
|
|
33
|
+
schema: "public",
|
|
34
|
+
table: "voorraad_publish_steps",
|
|
35
|
+
filter: `job_id=eq.${jobId}`,
|
|
36
|
+
}, () => void reload())
|
|
37
|
+
.on("postgres_changes", {
|
|
38
|
+
event: "*",
|
|
39
|
+
schema: "public",
|
|
40
|
+
table: "voorraad_publish_jobs",
|
|
41
|
+
filter: `id=eq.${jobId}`,
|
|
42
|
+
}, () => void reload())
|
|
43
|
+
.subscribe();
|
|
44
|
+
return () => {
|
|
45
|
+
void supabase.removeChannel(channel);
|
|
46
|
+
};
|
|
47
|
+
}, [jobId, reload]);
|
|
48
|
+
return { job, steps, loading, reload };
|
|
49
|
+
}
|
|
50
|
+
export function usePublishJobs(limit = 50) {
|
|
51
|
+
const [jobs, setJobs] = useState([]);
|
|
52
|
+
const [loading, setLoading] = useState(true);
|
|
53
|
+
const reload = useCallback(async () => {
|
|
54
|
+
setLoading(true);
|
|
55
|
+
const { data } = await supabase
|
|
56
|
+
.from("voorraad_publish_jobs")
|
|
57
|
+
.select("*")
|
|
58
|
+
.order("created_at", { ascending: false })
|
|
59
|
+
.limit(limit);
|
|
60
|
+
setJobs((data ?? []));
|
|
61
|
+
setLoading(false);
|
|
62
|
+
}, [limit]);
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
void reload();
|
|
65
|
+
}, [reload]);
|
|
66
|
+
return { jobs, loading, reload };
|
|
67
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRegisterModuleBaseUrl.d.ts","sourceRoot":"","sources":["../../src/hooks/useRegisterModuleBaseUrl.ts"],"names":[],"mappings":"AAUA,wBAAgB,wBAAwB,SA0BvC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registreert eenmalig per sessie de basis-URL van de shell waarin deze
|
|
3
|
+
* module draait, zodat de Postgres-cron de voorraadsync-hooks kan aanroepen
|
|
4
|
+
* zonder hardgecodeerde host.
|
|
5
|
+
*/
|
|
6
|
+
import { useEffect, useRef } from "react";
|
|
7
|
+
import { registerModuleBaseUrl } from "../lib/module-runtime-config.functions";
|
|
8
|
+
let alreadyRegistered = false;
|
|
9
|
+
export function useRegisterModuleBaseUrl() {
|
|
10
|
+
const started = useRef(false);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (alreadyRegistered || started.current)
|
|
13
|
+
return;
|
|
14
|
+
started.current = true;
|
|
15
|
+
alreadyRegistered = true;
|
|
16
|
+
registerModuleBaseUrl()
|
|
17
|
+
.then((res) => {
|
|
18
|
+
if (res?.ok) {
|
|
19
|
+
console.info(`[voorraad] basis-URL geregistreerd: ${res.baseUrl}${res.changed ? " (bijgewerkt)" : ""}`);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
alreadyRegistered = false;
|
|
23
|
+
console.warn(`[voorraad] basis-URL niet geregistreerd: ${res?.reason ?? "onbekende reden"}`);
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
.catch((e) => {
|
|
27
|
+
alreadyRegistered = false;
|
|
28
|
+
console.warn("[voorraad] kon basis-URL niet registreren:", e?.message ?? e);
|
|
29
|
+
});
|
|
30
|
+
}, []);
|
|
31
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface StockSyncHealth {
|
|
2
|
+
failed: number;
|
|
3
|
+
pending: number;
|
|
4
|
+
stalePending: number;
|
|
5
|
+
oldestPendingAt: string | null;
|
|
6
|
+
}
|
|
7
|
+
export declare function useStockSyncHealth(): import("@tanstack/react-query").UseQueryResult<NoInfer<StockSyncHealth>, Error>;
|
|
8
|
+
//# sourceMappingURL=useStockSyncHealth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStockSyncHealth.d.ts","sourceRoot":"","sources":["../../src/hooks/useStockSyncHealth.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,wBAAgB,kBAAkB,oFAmCjC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gezondheid van de voorraad-push-wachtrij richting Floriday.
|
|
3
|
+
* Signaleert vastgelopen (`failed`) of te lang wachtende (`pending`) regels.
|
|
4
|
+
*/
|
|
5
|
+
import { useQuery } from "@tanstack/react-query";
|
|
6
|
+
import { supabase } from "../integrations/supabase/client";
|
|
7
|
+
const STALE_MINUTES = 10;
|
|
8
|
+
export function useStockSyncHealth() {
|
|
9
|
+
return useQuery({
|
|
10
|
+
queryKey: ["stock-sync-health"],
|
|
11
|
+
refetchInterval: 60000,
|
|
12
|
+
queryFn: async () => {
|
|
13
|
+
const { data, error } = await supabase
|
|
14
|
+
.from("floriday_continuous_stock_queue")
|
|
15
|
+
.select("status, created_at")
|
|
16
|
+
.in("status", ["pending", "failed"])
|
|
17
|
+
.limit(1000);
|
|
18
|
+
if (error)
|
|
19
|
+
throw error;
|
|
20
|
+
const rows = (data ?? []);
|
|
21
|
+
const cutoff = Date.now() - STALE_MINUTES * 60000;
|
|
22
|
+
let failed = 0;
|
|
23
|
+
let pending = 0;
|
|
24
|
+
let stalePending = 0;
|
|
25
|
+
let oldestPendingAt = null;
|
|
26
|
+
for (const r of rows) {
|
|
27
|
+
if (r.status === "failed") {
|
|
28
|
+
failed++;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
pending++;
|
|
32
|
+
const ts = Date.parse(r.created_at);
|
|
33
|
+
if (Number.isFinite(ts) && ts < cutoff)
|
|
34
|
+
stalePending++;
|
|
35
|
+
if (!oldestPendingAt || r.created_at < oldestPendingAt) {
|
|
36
|
+
oldestPendingAt = r.created_at;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { failed, pending, stalePending, oldestPendingAt };
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTradeItemStock.d.ts","sourceRoot":"","sources":["../../src/hooks/useTradeItemStock.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAUD,wBAAgB,WAAW,CAAC,MAAM,EAAE;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG,MAAM,GAAG,IAAI,CAKhB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG,MAAM,EAAE,CAMX;AAED,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;;;mBA4ElB,iBAAiB;
|
|
1
|
+
{"version":3,"file":"useTradeItemStock.d.ts","sourceRoot":"","sources":["../../src/hooks/useTradeItemStock.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAUD,wBAAgB,WAAW,CAAC,MAAM,EAAE;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG,MAAM,GAAG,IAAI,CAKhB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG,MAAM,EAAE,CAMX;AAED,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;;;mBA4ElB,iBAAiB;EAmEnC;AAED,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAUzC"}
|