@flowselections/floriday-voorraad 1.0.86 → 1.0.87
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/FloridayTakeoverPanel.d.ts.map +1 -1
- package/dist-lib/components/voorraad/FloridayTakeoverPanel.js +12 -2
- package/dist-lib/integrations/supabase/types.d.ts +64 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/__tests__/floriday-fetch-status.test.d.ts +2 -0
- package/dist-lib/lib/__tests__/floriday-fetch-status.test.d.ts.map +1 -0
- package/dist-lib/lib/__tests__/floriday-fetch-status.test.js +25 -0
- package/dist-lib/lib/floriday-fetch-status.d.ts +17 -0
- package/dist-lib/lib/floriday-fetch-status.d.ts.map +1 -0
- package/dist-lib/lib/floriday-fetch-status.js +14 -0
- package/dist-lib/lib/floriday-takeover.functions.d.ts +16 -0
- package/dist-lib/lib/floriday-takeover.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-takeover.functions.js +50 -4
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloridayTakeoverPanel.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/FloridayTakeoverPanel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FloridayTakeoverPanel.d.ts","sourceRoot":"","sources":["../../../src/components/voorraad/FloridayTakeoverPanel.tsx"],"names":[],"mappings":"AA4CA,wBAAgB,sBAAsB,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCAoCvF;AAED,wBAAgB,qBAAqB,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,sCA2QtF"}
|
|
@@ -17,6 +17,10 @@ import { getFloridayTakeoverPreview } from "../../lib/floriday-takeover.function
|
|
|
17
17
|
const sb = supabase;
|
|
18
18
|
const eur = (v) => v == null ? "—" : `€ ${Number(v).toLocaleString("nl-NL", { minimumFractionDigits: 2, maximumFractionDigits: 4 })}`;
|
|
19
19
|
const num = (v) => (v == null ? "—" : Number(v).toLocaleString("nl-NL"));
|
|
20
|
+
function offersText(o) {
|
|
21
|
+
return o.map((x) => [x.customer ?? "Klant onbekend", x.price != null ? eur(x.price) : null, x.pieces != null ? `${num(x.pieces)} st.` : null,
|
|
22
|
+
x.from || x.to ? `${(x.from ?? "").slice(0, 10)} – ${(x.to ?? "").slice(0, 10)}` : null].filter(Boolean).join(" ")).join("; ");
|
|
23
|
+
}
|
|
20
24
|
function formsText(f) {
|
|
21
25
|
const parts = [];
|
|
22
26
|
if (f.continuous)
|
|
@@ -55,6 +59,8 @@ export function FloridayTakeoverPanel({ connectionId }) {
|
|
|
55
59
|
const [loading, setLoading] = useState(false);
|
|
56
60
|
const [rows, setRows] = useState(null);
|
|
57
61
|
const [weekError, setWeekError] = useState(null);
|
|
62
|
+
const [fetchStatus, setFetchStatus] = useState(null);
|
|
63
|
+
const itemsBlocked = fetchStatus != null && fetchStatus.tradeItems !== "compleet";
|
|
58
64
|
const [selected, setSelected] = useState(new Set());
|
|
59
65
|
const [busy, setBusy] = useState(false);
|
|
60
66
|
const [runs, setRuns] = useState([]);
|
|
@@ -88,6 +94,7 @@ export function FloridayTakeoverPanel({ connectionId }) {
|
|
|
88
94
|
const res = await preview();
|
|
89
95
|
setRows(res.rows);
|
|
90
96
|
setWeekError(res.weekError);
|
|
97
|
+
setFetchStatus(res.fetchStatus);
|
|
91
98
|
setSelected(new Set(res.rows.filter((r) => r.action !== "niet").map((r) => r.tradeItemId)));
|
|
92
99
|
}
|
|
93
100
|
catch (e) {
|
|
@@ -107,13 +114,14 @@ export function FloridayTakeoverPanel({ connectionId }) {
|
|
|
107
114
|
"Floriday aantal": r.floridayStock ?? "", "Bron aantal": r.stockSource ?? "",
|
|
108
115
|
"Prijs aanbodregel": r.supplyLinePrice ?? "", Catalogusprijs: r.catalogPrice ?? "", "Gekozen prijs": r.floridayPrice ?? "", "Bron prijs": r.priceSource ?? "",
|
|
109
116
|
"Eigen voorraad": r.erpStock ?? "", "Eigen prijs": r.erpPrice ?? "", Aanbodvorm: formsText(r.forms),
|
|
117
|
+
Klantaanbiedingen: offersText(r.customerOffers),
|
|
110
118
|
}));
|
|
111
119
|
const wb = XLSX.utils.book_new();
|
|
112
120
|
XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(data), "Proefrapport");
|
|
113
121
|
XLSX.writeFile(wb, `overnemen-uit-floriday-${new Date().toISOString().slice(0, 10)}.xlsx`);
|
|
114
122
|
};
|
|
115
123
|
const apply = async () => {
|
|
116
|
-
if (!connectionId || chosen.length === 0)
|
|
124
|
+
if (!connectionId || chosen.length === 0 || itemsBlocked)
|
|
117
125
|
return;
|
|
118
126
|
const created = chosen.filter((r) => r.action === "aanmaken").length;
|
|
119
127
|
if (!window.confirm(`${chosen.length} artikelen overnemen uit Floriday${created ? `, waarvan ${created} nieuw aanmaken` : ""}? ` +
|
|
@@ -179,7 +187,9 @@ export function FloridayTakeoverPanel({ connectionId }) {
|
|
|
179
187
|
};
|
|
180
188
|
if (!connectionId)
|
|
181
189
|
return null;
|
|
182
|
-
return (_jsxs("section", { className: "rounded-md border p-3 space-y-3", children: [_jsxs("button", { type: "button", className: "text-sm font-medium", onClick: () => setOpen((v) => !v), children: [open ? "▾" : "▸", " Overnemen uit Floriday en eigen voorraad leidend maken"] }), open && (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm text-muted-foreground", children: "Neem voorraad en prijs over uit Floriday zonder iets terug te sturen. Maak eerst een proefrapport; er wordt dan nog niets gewijzigd." }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Button, { size: "sm", onClick: runPreview, disabled: loading, children: loading ? "Floriday lezen…" : "Proefrapport maken" }), rows && _jsx(Button, { size: "sm", variant: "outline", onClick: download, children: "Download als Excel" }), rows && _jsx(Button, { size: "sm", onClick: apply, disabled: busy || chosen.length === 0, children: busy ? "Bezig…" : `Overnemen (${chosen.length})` })] }),
|
|
190
|
+
return (_jsxs("section", { className: "rounded-md border p-3 space-y-3", children: [_jsxs("button", { type: "button", className: "text-sm font-medium", onClick: () => setOpen((v) => !v), children: [open ? "▾" : "▸", " Overnemen uit Floriday en eigen voorraad leidend maken"] }), open && (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm text-muted-foreground", children: "Neem voorraad en prijs over uit Floriday zonder iets terug te sturen. Maak eerst een proefrapport; er wordt dan nog niets gewijzigd." }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Button, { size: "sm", onClick: runPreview, disabled: loading, children: loading ? "Floriday lezen…" : "Proefrapport maken" }), rows && _jsx(Button, { size: "sm", variant: "outline", onClick: download, children: "Download als Excel" }), rows && _jsx(Button, { size: "sm", onClick: apply, disabled: busy || chosen.length === 0 || itemsBlocked, children: busy ? "Bezig…" : `Overnemen (${chosen.length})` })] }), fetchStatus && fetchStatus.tradeItems !== "compleet" && (_jsx("p", { className: "text-sm text-destructive", children: fetchStatus.tradeItems === "bezig"
|
|
191
|
+
? "Artikelen worden nog opgehaald – wacht tot dit compleet is. Overnemen kan daarna."
|
|
192
|
+
: "De artikelen uit Floriday zijn nog niet opgehaald – wacht tot dit compleet is. Overnemen kan daarna." })), fetchStatus && fetchStatus.tradeItems === "compleet" && (fetchStatus.catalogPrices === "bezig" || fetchStatus.customerOffers === "bezig") && (_jsx("p", { className: "text-sm text-muted-foreground", children: "Het aanbod wordt nog opgehaald \u2013 wacht tot dit compleet is voor de juiste prijzen. Maak daarna het proefrapport opnieuw." })), weekError && (_jsxs("p", { className: "text-sm text-destructive", children: ["Het weekaanbod kon niet worden gelezen; het rapport gebruikt alleen de overige gegevens.", " ", _jsxs("details", { className: "inline", children: [_jsx("summary", { className: "inline cursor-pointer", children: "Details voor beheer" }), weekError] })] })), rows && (_jsx("div", { className: "max-h-[28rem] overflow-auto rounded border", children: _jsxs("table", { className: "w-full text-xs", children: [_jsx("thead", { className: "sticky top-0 bg-muted", children: _jsxs("tr", { className: "text-left", children: [_jsx("th", { className: "p-1" }), _jsx("th", { className: "p-1", children: "Artikel" }), _jsx("th", { className: "p-1", children: "Actie" }), _jsx("th", { className: "p-1", children: "Floriday aantal" }), _jsx("th", { className: "p-1", children: "Floriday prijs" }), _jsx("th", { className: "p-1", children: "Nu in je voorraad" }), _jsx("th", { className: "p-1", children: "Aanbodvorm" })] }) }), _jsx("tbody", { children: rows.map((r) => (_jsxs("tr", { className: "border-t align-top", children: [_jsx("td", { className: "p-1", children: _jsx("input", { type: "checkbox", disabled: r.action === "niet", checked: selected.has(r.tradeItemId), onChange: (e) => setSelected((s) => { const n = new Set(s); e.target.checked ? n.add(r.tradeItemId) : n.delete(r.tradeItemId); return n; }) }) }), _jsxs("td", { className: "p-1", children: [_jsx("div", { className: "font-medium", children: r.name }), _jsx("div", { className: "text-muted-foreground", children: [r.articleCode, r.gtin, r.vbnCode && `VBN ${r.vbnCode}`].filter(Boolean).join(" · ") }), r.suggestion && _jsx("div", { className: "text-amber-700", children: r.suggestion })] }), _jsxs("td", { className: "p-1", children: [r.action === "aanmaken" ? "Nieuw aanmaken (Uit)" : r.action === "bijwerken" ? "Bijwerken" : "Niet over te nemen", r.reason && _jsx("div", { className: "text-muted-foreground", children: r.reason })] }), _jsxs("td", { className: "p-1", children: [num(r.floridayStock), _jsx("div", { className: "text-muted-foreground", children: r.stockSource ?? "" })] }), _jsxs("td", { className: "p-1", children: [eur(r.floridayPrice), _jsx("div", { className: "text-muted-foreground", children: r.priceSource ?? "" }), r.priceDiffers && _jsxs("div", { className: "text-amber-700", children: ["Aanbodregel ", eur(r.supplyLinePrice), " \u00B7 catalogus ", eur(r.catalogPrice)] })] }), _jsxs("td", { className: "p-1", children: [num(r.erpStock), " \u00B7 ", eur(r.erpPrice)] }), _jsxs("td", { className: "p-1", children: [formsText(r.forms), r.customerOffers.length > 0 && (_jsxs("details", { children: [_jsxs("summary", { className: "cursor-pointer", children: ["Klantaanbiedingen (", r.customerOffers.length, ", alleen getoond)"] }), _jsx("ul", { className: "list-disc pl-4", children: r.customerOffers.map((o) => _jsx("li", { children: offersText([o]) }, o.id)) })] }))] })] }, r.tradeItemId))) })] }) })), runs.length > 0 && (_jsxs("div", { className: "text-sm space-y-1", children: [_jsx("div", { className: "font-medium", children: "Laatste overnames" }), runs.map((r) => (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("span", { children: [new Date(r.created_at).toLocaleString("nl-NL"), " \u2014 ", r.total_items, " artikelen", r.created_products ? `, ${r.created_products} nieuw` : "", " \u2014 ", r.status] }), r.status !== "ongedaan" && _jsx(Button, { size: "sm", variant: "outline", onClick: () => undo(r.id), children: "Terugdraaien" })] }, r.id)))] }))] }), _jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "text-sm font-medium", children: "Eigen voorraad leidend maken" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Kies artikelen die nu Floriday-leidend zijn. Je ziet eerst wat er naar Floriday zou gaan; pas na bevestigen verandert er iets." }), leadRows.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Er zijn geen Floriday-leidende artikelen." })) : (_jsxs("div", { className: "max-h-48 overflow-auto rounded border p-2 text-sm space-y-1", children: [_jsxs("label", { className: "flex items-center gap-2 font-medium", children: [_jsx("input", { type: "checkbox", checked: leadSel.size === leadRows.length, onChange: (e) => setLeadSel(e.target.checked ? new Set(leadRows.map((r) => r.product_id)) : new Set()) }), "Alles kiezen"] }), leadRows.map((r) => (_jsxs("label", { className: "flex items-center gap-2", children: [_jsx("input", { type: "checkbox", checked: leadSel.has(r.product_id), onChange: (e) => setLeadSel((s) => { const n = new Set(s); e.target.checked ? n.add(r.product_id) : n.delete(r.product_id); return n; }) }), r.name] }, r.product_id)))] })), _jsxs(Button, { size: "sm", variant: "outline", disabled: leadSel.size === 0, onClick: showErpPreview, children: ["Voorbeeld tonen (", leadSel.size, ")"] }), erpPreview && (_jsxs("div", { className: "space-y-2", children: [_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Alleen de huidige week en de komende ", erpPreview[0]?.horizon_weeks ?? "?", " weken worden aangepast; weken in het verleden nooit."] }), _jsxs("table", { className: "w-full text-xs rounded border", children: [_jsx("thead", { className: "bg-muted", children: _jsxs("tr", { className: "text-left", children: [_jsx("th", { className: "p-1", children: "Artikel" }), _jsx("th", { className: "p-1", children: "Week" }), _jsx("th", { className: "p-1", children: "Vorm" }), _jsx("th", { className: "p-1", children: "Aantal" }), _jsx("th", { className: "p-1", children: "Prijs per stuk" }), _jsx("th", { className: "p-1", children: "Nu in Floriday" }), _jsx("th", { className: "p-1", children: "Let op" })] }) }), _jsx("tbody", { children: erpPreview.flatMap((r) => {
|
|
183
193
|
const ws = r.weeks?.length ? r.weeks : [null];
|
|
184
194
|
return ws.map((w, i) => (_jsxs("tr", { className: "border-t align-top", children: [_jsx("td", { className: "p-1", children: i === 0 ? r.product_name : "" }), _jsx("td", { className: "p-1", children: w ? (w.week != null ? `${w.year} wk ${w.week}` : "Doorlopend") : "—" }), _jsx("td", { className: "p-1", children: w ? (w.form === "continuous" ? "Doorlopende voorraad" : "Weekaanbod") : "—" }), _jsx("td", { className: "p-1", children: w ? _jsxs(_Fragment, { children: [num(w.quantity), w.available === false ? " (niet beschikbaar)" : ""] }) : "—" }), _jsx("td", { className: "p-1", children: w ? eur(w.price) : eur(r.sale_price) }), _jsx("td", { className: "p-1", children: w && w.floriday_pieces != null ? num(w.floriday_pieces) : "onbekend" }), _jsx("td", { className: "p-1 text-amber-700", children: i === 0 ? r.blocker ?? "" : "" })] }, `${r.product_id}-${i}`)));
|
|
185
195
|
}) })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { size: "sm", onClick: confirmErp, children: "Bevestigen" }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => setErpPreview(null), children: "Annuleren" })] })] }))] })] }))] }));
|
|
@@ -7065,6 +7065,44 @@ export type Database = {
|
|
|
7065
7065
|
}
|
|
7066
7066
|
];
|
|
7067
7067
|
};
|
|
7068
|
+
floriday_customer_offers_cache: {
|
|
7069
|
+
Row: {
|
|
7070
|
+
connection_id: string;
|
|
7071
|
+
data: Json;
|
|
7072
|
+
fetched_at: string;
|
|
7073
|
+
floriday_id: string;
|
|
7074
|
+
is_deleted: boolean;
|
|
7075
|
+
sequence_number: number;
|
|
7076
|
+
updated_at: string;
|
|
7077
|
+
};
|
|
7078
|
+
Insert: {
|
|
7079
|
+
connection_id: string;
|
|
7080
|
+
data?: Json;
|
|
7081
|
+
fetched_at?: string;
|
|
7082
|
+
floriday_id: string;
|
|
7083
|
+
is_deleted?: boolean;
|
|
7084
|
+
sequence_number?: number;
|
|
7085
|
+
updated_at?: string;
|
|
7086
|
+
};
|
|
7087
|
+
Update: {
|
|
7088
|
+
connection_id?: string;
|
|
7089
|
+
data?: Json;
|
|
7090
|
+
fetched_at?: string;
|
|
7091
|
+
floriday_id?: string;
|
|
7092
|
+
is_deleted?: boolean;
|
|
7093
|
+
sequence_number?: number;
|
|
7094
|
+
updated_at?: string;
|
|
7095
|
+
};
|
|
7096
|
+
Relationships: [
|
|
7097
|
+
{
|
|
7098
|
+
foreignKeyName: "floriday_customer_offers_cache_connection_id_fkey";
|
|
7099
|
+
columns: ["connection_id"];
|
|
7100
|
+
isOneToOne: false;
|
|
7101
|
+
referencedRelation: "floriday_connections";
|
|
7102
|
+
referencedColumns: ["id"];
|
|
7103
|
+
}
|
|
7104
|
+
];
|
|
7105
|
+
};
|
|
7068
7106
|
floriday_customer_sticker_pdfs_cache: {
|
|
7069
7107
|
Row: {
|
|
7070
7108
|
byte_size: number | null;
|
|
@@ -8517,33 +8555,45 @@ export type Database = {
|
|
|
8517
8555
|
};
|
|
8518
8556
|
floriday_sync_state: {
|
|
8519
8557
|
Row: {
|
|
8558
|
+
backfill_done_at: string | null;
|
|
8559
|
+
backfill_started_at: string | null;
|
|
8560
|
+
backfill_target_sequence: number | null;
|
|
8520
8561
|
connection_id: string;
|
|
8521
8562
|
entity_type: string;
|
|
8522
8563
|
last_error: string | null;
|
|
8523
8564
|
last_items_processed: number | null;
|
|
8524
8565
|
last_max_sequence_seen: number | null;
|
|
8566
|
+
last_rate_limited_at: string | null;
|
|
8525
8567
|
last_sequence_number: number;
|
|
8526
8568
|
last_success_at: string | null;
|
|
8527
8569
|
last_synced_at: string | null;
|
|
8528
8570
|
updated_at: string;
|
|
8529
8571
|
};
|
|
8530
8572
|
Insert: {
|
|
8573
|
+
backfill_done_at?: string | null;
|
|
8574
|
+
backfill_started_at?: string | null;
|
|
8575
|
+
backfill_target_sequence?: number | null;
|
|
8531
8576
|
connection_id: string;
|
|
8532
8577
|
entity_type: string;
|
|
8533
8578
|
last_error?: string | null;
|
|
8534
8579
|
last_items_processed?: number | null;
|
|
8535
8580
|
last_max_sequence_seen?: number | null;
|
|
8581
|
+
last_rate_limited_at?: string | null;
|
|
8536
8582
|
last_sequence_number?: number;
|
|
8537
8583
|
last_success_at?: string | null;
|
|
8538
8584
|
last_synced_at?: string | null;
|
|
8539
8585
|
updated_at?: string;
|
|
8540
8586
|
};
|
|
8541
8587
|
Update: {
|
|
8588
|
+
backfill_done_at?: string | null;
|
|
8589
|
+
backfill_started_at?: string | null;
|
|
8590
|
+
backfill_target_sequence?: number | null;
|
|
8542
8591
|
connection_id?: string;
|
|
8543
8592
|
entity_type?: string;
|
|
8544
8593
|
last_error?: string | null;
|
|
8545
8594
|
last_items_processed?: number | null;
|
|
8546
8595
|
last_max_sequence_seen?: number | null;
|
|
8596
|
+
last_rate_limited_at?: string | null;
|
|
8547
8597
|
last_sequence_number?: number;
|
|
8548
8598
|
last_success_at?: string | null;
|
|
8549
8599
|
last_synced_at?: string | null;
|
|
@@ -30728,6 +30778,13 @@ export type Database = {
|
|
|
30728
30778
|
};
|
|
30729
30779
|
Returns: Json;
|
|
30730
30780
|
};
|
|
30781
|
+
floriday_takeover_fetch_state: {
|
|
30782
|
+
Args: {
|
|
30783
|
+
p_connection_id: string;
|
|
30784
|
+
p_entity?: string;
|
|
30785
|
+
};
|
|
30786
|
+
Returns: string;
|
|
30787
|
+
};
|
|
30731
30788
|
floriday_takeover_undo: {
|
|
30732
30789
|
Args: {
|
|
30733
30790
|
p_run_id: string;
|
|
@@ -37085,6 +37142,13 @@ export type Database = {
|
|
|
37085
37142
|
};
|
|
37086
37143
|
Returns: number;
|
|
37087
37144
|
};
|
|
37145
|
+
schedule_floriday_customer_offers_sync: {
|
|
37146
|
+
Args: {
|
|
37147
|
+
p_apikey: string;
|
|
37148
|
+
p_url: string;
|
|
37149
|
+
};
|
|
37150
|
+
Returns: number;
|
|
37151
|
+
};
|
|
37088
37152
|
schedule_floriday_customer_organizations_sync: {
|
|
37089
37153
|
Args: {
|
|
37090
37154
|
p_apikey: string;
|