@flowselections/floriday-afhandeling-module 1.0.9 → 1.0.11
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/afhandeling/ControleLijstPrint.d.ts +7 -0
- package/dist-lib/components/afhandeling/ControleLijstPrint.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/ControleLijstPrint.js +67 -0
- package/dist-lib/components/afhandeling/ControlePage.d.ts +2 -0
- package/dist-lib/components/afhandeling/ControlePage.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/ControlePage.js +456 -0
- package/dist-lib/components/afhandeling/DagDetailDialog.d.ts +9 -0
- package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/DagDetailDialog.js +149 -0
- package/dist-lib/components/afhandeling/LeveringenPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/LeveringenPage.js +11 -5
- package/dist-lib/components/afhandeling/PickAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/PickAgendaView.js +13 -4
- package/dist-lib/components/afhandeling/PlanningAgendaPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/PlanningAgendaPage.js +2 -2
- package/dist-lib/components/afhandeling/ServiceAreaSelect.d.ts +12 -0
- package/dist-lib/components/afhandeling/ServiceAreaSelect.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/ServiceAreaSelect.js +79 -0
- package/dist-lib/components/afhandeling/VervoerderForm.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/VervoerderForm.js +62 -6
- package/dist-lib/components/afhandeling/VervoerdersPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/VervoerdersPage.js +25 -6
- package/dist-lib/components/afhandeling/WeekAgendaView.d.ts +2 -1
- package/dist-lib/components/afhandeling/WeekAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/WeekAgendaView.js +63 -18
- package/dist-lib/components/afhandeling/WeekdayPicker.d.ts +12 -0
- package/dist-lib/components/afhandeling/WeekdayPicker.d.ts.map +1 -0
- package/dist-lib/components/afhandeling/WeekdayPicker.js +30 -0
- package/dist-lib/components/pickstation/PakbonTemplate.d.ts +6 -2
- package/dist-lib/components/pickstation/PakbonTemplate.d.ts.map +1 -1
- package/dist-lib/components/pickstation/PakbonTemplate.js +37 -12
- package/dist-lib/components/settings/AfhandelingSettingsCard.d.ts.map +1 -1
- package/dist-lib/components/settings/AfhandelingSettingsCard.js +25 -6
- package/dist-lib/components/ui/responsive-dialog.d.ts +20 -0
- package/dist-lib/components/ui/responsive-dialog.d.ts.map +1 -0
- package/dist-lib/components/ui/responsive-dialog.js +44 -0
- package/dist-lib/hooks/useOrderPlanning.d.ts +3 -0
- package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -1
- package/dist-lib/hooks/useOrderPlanning.js +64 -12
- package/dist-lib/index.d.ts +1 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +4 -2
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +2898 -147
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +2898 -147
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +2898 -147
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +2986 -155
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/afhandelingSettings.functions.d.ts +10666 -5151
- package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -1
- package/dist-lib/lib/afhandelingSettings.functions.js +42 -2
- package/dist-lib/lib/carrierMatch.server.d.ts +27 -0
- package/dist-lib/lib/carrierMatch.server.d.ts.map +1 -0
- package/dist-lib/lib/carrierMatch.server.js +75 -0
- package/dist-lib/lib/carrierSignupMail.server.d.ts +56 -0
- package/dist-lib/lib/carrierSignupMail.server.d.ts.map +1 -0
- package/dist-lib/lib/carrierSignupMail.server.js +229 -0
- package/dist-lib/lib/carriers.functions.d.ts +36404 -15470
- package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
- package/dist-lib/lib/carriers.functions.js +43 -2
- package/dist-lib/lib/cartAssignments.functions.d.ts +49609 -0
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -0
- package/dist-lib/lib/cartAssignments.functions.js +130 -0
- package/dist-lib/lib/cartControl.functions.d.ts +99259 -0
- package/dist-lib/lib/cartControl.functions.d.ts.map +1 -0
- package/dist-lib/lib/cartControl.functions.js +489 -0
- package/dist-lib/lib/cartMoveImpact.d.ts +8 -0
- package/dist-lib/lib/cartMoveImpact.d.ts.map +1 -0
- package/dist-lib/lib/cartMoveImpact.js +26 -0
- package/dist-lib/lib/cartRescheduling.d.ts +30 -0
- package/dist-lib/lib/cartRescheduling.d.ts.map +1 -0
- package/dist-lib/lib/cartRescheduling.js +71 -0
- package/dist-lib/lib/floriday.functions.d.ts +2902 -147
- package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday.functions.js +178 -98
- package/dist-lib/lib/geo/euServiceAreas.d.ts +30 -0
- package/dist-lib/lib/geo/euServiceAreas.d.ts.map +1 -0
- package/dist-lib/lib/geo/euServiceAreas.js +277 -0
- package/dist-lib/lib/invalidatePlanning.d.ts +11 -0
- package/dist-lib/lib/invalidatePlanning.d.ts.map +1 -0
- package/dist-lib/lib/invalidatePlanning.js +25 -0
- package/dist-lib/lib/pickstationI18n.d.ts +12 -0
- package/dist-lib/lib/pickstationI18n.d.ts.map +1 -1
- package/dist-lib/lib/pickstationI18n.js +72 -0
- package/dist-lib/lib/pickstationOrders.server.d.ts +2 -1
- package/dist-lib/lib/pickstationOrders.server.d.ts.map +1 -1
- package/dist-lib/lib/pickstationOrders.server.js +393 -178
- package/dist-lib/lib/pickstationTypes.d.ts +23 -2
- package/dist-lib/lib/pickstationTypes.d.ts.map +1 -1
- package/dist-lib/lib/planning.d.ts +41 -2
- package/dist-lib/lib/planning.d.ts.map +1 -1
- package/dist-lib/lib/planning.js +159 -36
- package/package.json +2 -2
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Server-only helper: pick the responsible carrier for an order based on
|
|
2
|
+
// the carrier's service area (country/province/city). Falls back to the
|
|
3
|
+
// carrier flagged is_default when nothing matches.
|
|
4
|
+
import { matchesServiceArea } from "./geo/euServiceAreas";
|
|
5
|
+
// Common country names → ISO 3166-1 alpha-2. Keep it small; anything else
|
|
6
|
+
// falls back to the default carrier.
|
|
7
|
+
const COUNTRY_MAP = {
|
|
8
|
+
nl: "NL", nederland: "NL", holland: "NL", netherlands: "NL", "the netherlands": "NL",
|
|
9
|
+
be: "BE", belgie: "BE", belgië: "BE", belgium: "BE", belgique: "BE",
|
|
10
|
+
de: "DE", duitsland: "DE", germany: "DE", deutschland: "DE",
|
|
11
|
+
fr: "FR", frankrijk: "FR", france: "FR",
|
|
12
|
+
lu: "LU", luxemburg: "LU", luxembourg: "LU",
|
|
13
|
+
gb: "GB", uk: "GB", "verenigd koninkrijk": "GB", "united kingdom": "GB", england: "GB",
|
|
14
|
+
ch: "CH", zwitserland: "CH", switzerland: "CH",
|
|
15
|
+
at: "AT", oostenrijk: "AT", austria: "AT",
|
|
16
|
+
it: "IT", italie: "IT", italië: "IT", italy: "IT",
|
|
17
|
+
es: "ES", spanje: "ES", spain: "ES",
|
|
18
|
+
pt: "PT", portugal: "PT",
|
|
19
|
+
pl: "PL", polen: "PL", poland: "PL",
|
|
20
|
+
dk: "DK", denemarken: "DK", denmark: "DK",
|
|
21
|
+
se: "SE", zweden: "SE", sweden: "SE",
|
|
22
|
+
no: "NO", noorwegen: "NO", norway: "NO",
|
|
23
|
+
fi: "FI", finland: "FI",
|
|
24
|
+
ie: "IE", ierland: "IE", ireland: "IE",
|
|
25
|
+
cz: "CZ", tsjechie: "CZ", tsjechië: "CZ", "czech republic": "CZ", czechia: "CZ",
|
|
26
|
+
hu: "HU", hongarije: "HU", hungary: "HU",
|
|
27
|
+
ro: "RO", roemenie: "RO", roemenië: "RO", romania: "RO",
|
|
28
|
+
bg: "BG", bulgarije: "BG", bulgaria: "BG",
|
|
29
|
+
sk: "SK", slowakije: "SK", slovakia: "SK",
|
|
30
|
+
si: "SI", slovenie: "SI", slovenië: "SI", slovenia: "SI",
|
|
31
|
+
hr: "HR", kroatie: "HR", kroatië: "HR", croatia: "HR",
|
|
32
|
+
gr: "GR", griekenland: "GR", greece: "GR",
|
|
33
|
+
ee: "EE", estland: "EE", estonia: "EE",
|
|
34
|
+
lv: "LV", letland: "LV", latvia: "LV",
|
|
35
|
+
lt: "LT", litouwen: "LT", lithuania: "LT",
|
|
36
|
+
mt: "MT", malta: "MT",
|
|
37
|
+
cy: "CY", cyprus: "CY",
|
|
38
|
+
};
|
|
39
|
+
export function normalizeCountry(raw) {
|
|
40
|
+
if (!raw)
|
|
41
|
+
return null;
|
|
42
|
+
const s = raw.trim();
|
|
43
|
+
if (!s)
|
|
44
|
+
return null;
|
|
45
|
+
if (/^[A-Z]{2}$/.test(s))
|
|
46
|
+
return s;
|
|
47
|
+
const iso = COUNTRY_MAP[s.toLowerCase()];
|
|
48
|
+
return iso ?? null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Pick the carrier responsible for the given order address. Carriers are
|
|
52
|
+
* tried in ascending sort_order; the first one whose service area covers
|
|
53
|
+
* the address wins. If no carrier matches, the carrier with is_default =
|
|
54
|
+
* true is returned. Returns null when neither is available.
|
|
55
|
+
*/
|
|
56
|
+
export function pickCarrierForAddress(carriers, address) {
|
|
57
|
+
const sorted = [...carriers].sort((a, b) => (a.sort_order ?? 9999) - (b.sort_order ?? 9999));
|
|
58
|
+
const target = {
|
|
59
|
+
country: normalizeCountry(address.country),
|
|
60
|
+
province: address.province ?? null,
|
|
61
|
+
city: address.city ?? null,
|
|
62
|
+
};
|
|
63
|
+
for (const c of sorted) {
|
|
64
|
+
if (!c.email)
|
|
65
|
+
continue;
|
|
66
|
+
const matched = matchesServiceArea({
|
|
67
|
+
countries: c.service_countries ?? [],
|
|
68
|
+
provinces: c.service_provinces ?? [],
|
|
69
|
+
cities: c.service_cities ?? [],
|
|
70
|
+
}, target);
|
|
71
|
+
if (matched)
|
|
72
|
+
return c;
|
|
73
|
+
}
|
|
74
|
+
return sorted.find((c) => c.is_default && c.email) ?? null;
|
|
75
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export interface SignupMailOrderItem {
|
|
2
|
+
name: string;
|
|
3
|
+
quantity: number | null;
|
|
4
|
+
unit: string | null;
|
|
5
|
+
}
|
|
6
|
+
export interface SignupMailCustomer {
|
|
7
|
+
name: string;
|
|
8
|
+
contactPerson?: string | null;
|
|
9
|
+
email?: string | null;
|
|
10
|
+
phone?: string | null;
|
|
11
|
+
customerNumber?: string | null;
|
|
12
|
+
}
|
|
13
|
+
export interface SignupMailAddress {
|
|
14
|
+
name?: string | null;
|
|
15
|
+
street?: string | null;
|
|
16
|
+
houseNumber?: string | null;
|
|
17
|
+
postalCode?: string | null;
|
|
18
|
+
city?: string | null;
|
|
19
|
+
province?: string | null;
|
|
20
|
+
country?: string | null;
|
|
21
|
+
}
|
|
22
|
+
export interface SignupMailOrderDetail {
|
|
23
|
+
orderNumber: string;
|
|
24
|
+
orderDate?: string | null;
|
|
25
|
+
deliveryDate?: string | null;
|
|
26
|
+
deliveryType: string;
|
|
27
|
+
notes?: string | null;
|
|
28
|
+
cartCount: number | null;
|
|
29
|
+
plantCount: number | null;
|
|
30
|
+
customer: SignupMailCustomer;
|
|
31
|
+
deliveryLocation?: SignupMailAddress | null;
|
|
32
|
+
pickupLocations?: string[];
|
|
33
|
+
items?: SignupMailOrderItem[];
|
|
34
|
+
}
|
|
35
|
+
export interface SignupMailOrderRow {
|
|
36
|
+
orderNumber: string;
|
|
37
|
+
customerName: string;
|
|
38
|
+
deliveryType: string;
|
|
39
|
+
cartCount: number | null;
|
|
40
|
+
plantCount: number | null;
|
|
41
|
+
}
|
|
42
|
+
export interface SignupMailInput {
|
|
43
|
+
carrierName: string;
|
|
44
|
+
pickupDate: Date;
|
|
45
|
+
pickupTime: string;
|
|
46
|
+
signupDeadline: Date;
|
|
47
|
+
orders: SignupMailOrderDetail[];
|
|
48
|
+
}
|
|
49
|
+
export declare function buildCarrierSignupMail(input: SignupMailInput): {
|
|
50
|
+
subject: string;
|
|
51
|
+
html: string;
|
|
52
|
+
text: string;
|
|
53
|
+
totalCarts: number;
|
|
54
|
+
totalPlants: number;
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=carrierSignupMail.server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"carrierSignupMail.server.d.ts","sourceRoot":"","sources":["../../src/lib/carrierSignupMail.server.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,gBAAgB,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC5C,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC/B;AAGD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,IAAI,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,IAAI,CAAC;IACrB,MAAM,EAAE,qBAAqB,EAAE,CAAC;CACjC;AAgJD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,eAAe,GAAG;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB,CAoGA"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// Server-only HTML/text builder for carrier signup digest e-mails.
|
|
2
|
+
function fmtDate(d) {
|
|
3
|
+
return d.toLocaleDateString("nl-NL", {
|
|
4
|
+
weekday: "long",
|
|
5
|
+
day: "2-digit",
|
|
6
|
+
month: "long",
|
|
7
|
+
year: "numeric",
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
function fmtDateTime(d) {
|
|
11
|
+
return d.toLocaleString("nl-NL", {
|
|
12
|
+
weekday: "short",
|
|
13
|
+
day: "2-digit",
|
|
14
|
+
month: "short",
|
|
15
|
+
hour: "2-digit",
|
|
16
|
+
minute: "2-digit",
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function fmtIsoDate(s) {
|
|
20
|
+
if (!s)
|
|
21
|
+
return "Onbekend";
|
|
22
|
+
const d = new Date(s);
|
|
23
|
+
if (Number.isNaN(d.getTime()))
|
|
24
|
+
return s;
|
|
25
|
+
return d.toLocaleDateString("nl-NL", { day: "2-digit", month: "long", year: "numeric" });
|
|
26
|
+
}
|
|
27
|
+
function val(s) {
|
|
28
|
+
const v = (s ?? "").trim();
|
|
29
|
+
return v === "" ? "Onbekend" : escape(v);
|
|
30
|
+
}
|
|
31
|
+
function renderAddress(a) {
|
|
32
|
+
if (!a)
|
|
33
|
+
return `<div style="color:#6b7280;">Onbekend</div>`;
|
|
34
|
+
const streetLine = [a.street, a.houseNumber].filter(Boolean).join(" ").trim();
|
|
35
|
+
const cityLine = [a.postalCode, a.city].filter(Boolean).join(" ").trim();
|
|
36
|
+
const lines = [];
|
|
37
|
+
if (a.name && a.name.trim())
|
|
38
|
+
lines.push(`<strong>${escape(a.name)}</strong>`);
|
|
39
|
+
if (streetLine)
|
|
40
|
+
lines.push(escape(streetLine));
|
|
41
|
+
if (cityLine)
|
|
42
|
+
lines.push(escape(cityLine));
|
|
43
|
+
if (a.province && a.province.trim())
|
|
44
|
+
lines.push(escape(a.province));
|
|
45
|
+
if (a.country && a.country.trim())
|
|
46
|
+
lines.push(escape(a.country));
|
|
47
|
+
if (lines.length === 0)
|
|
48
|
+
return `<div style="color:#6b7280;">Onbekend</div>`;
|
|
49
|
+
return lines.map((l) => `<div>${l}</div>`).join("");
|
|
50
|
+
}
|
|
51
|
+
function renderDefinitionList(rows) {
|
|
52
|
+
return `<table style="border-collapse:collapse;font-size:13px;width:100%;">${rows
|
|
53
|
+
.map((r) => `
|
|
54
|
+
<tr>
|
|
55
|
+
<td style="padding:2px 12px 2px 0;color:#6b7280;width:140px;vertical-align:top;">${escape(r.label)}</td>
|
|
56
|
+
<td style="padding:2px 0;vertical-align:top;">${r.value}</td>
|
|
57
|
+
</tr>`)
|
|
58
|
+
.join("")}</table>`;
|
|
59
|
+
}
|
|
60
|
+
function renderItemsTable(items) {
|
|
61
|
+
if (!items || items.length === 0) {
|
|
62
|
+
return `<div style="color:#6b7280;font-size:13px;">Geen artikelen geregistreerd.</div>`;
|
|
63
|
+
}
|
|
64
|
+
const rows = items
|
|
65
|
+
.map((it) => `
|
|
66
|
+
<tr>
|
|
67
|
+
<td style="padding:6px 8px;border-bottom:1px solid #e5e7eb;">${escape(it.name)}</td>
|
|
68
|
+
<td style="padding:6px 8px;border-bottom:1px solid #e5e7eb;text-align:right;">${it.quantity ?? "—"}</td>
|
|
69
|
+
<td style="padding:6px 8px;border-bottom:1px solid #e5e7eb;">${escape(it.unit ?? "")}</td>
|
|
70
|
+
</tr>`)
|
|
71
|
+
.join("");
|
|
72
|
+
return `<table style="border-collapse:collapse;width:100%;font-size:13px;">
|
|
73
|
+
<thead><tr style="background:#f3f4f6;text-align:left;">
|
|
74
|
+
<th style="padding:6px 8px;">Artikel</th>
|
|
75
|
+
<th style="padding:6px 8px;text-align:right;width:90px;">Aantal</th>
|
|
76
|
+
<th style="padding:6px 8px;width:100px;">Eenheid</th>
|
|
77
|
+
</tr></thead>
|
|
78
|
+
<tbody>${rows}</tbody>
|
|
79
|
+
</table>`;
|
|
80
|
+
}
|
|
81
|
+
function renderOrderBlock(o) {
|
|
82
|
+
const orderRows = renderDefinitionList([
|
|
83
|
+
{ label: "Ordernummer", value: `<strong>${val(o.orderNumber)}</strong>` },
|
|
84
|
+
{ label: "Besteldatum", value: escape(fmtIsoDate(o.orderDate)) },
|
|
85
|
+
{ label: "Gewenste leverdatum", value: escape(fmtIsoDate(o.deliveryDate)) },
|
|
86
|
+
{ label: "Type levering", value: val(o.deliveryType) },
|
|
87
|
+
{ label: "Karren", value: String(o.cartCount ?? "—") },
|
|
88
|
+
{ label: "Planten", value: String(o.plantCount ?? "—") },
|
|
89
|
+
]);
|
|
90
|
+
const customerRows = renderDefinitionList([
|
|
91
|
+
{ label: "Klantnaam", value: val(o.customer.name) },
|
|
92
|
+
{ label: "E-mailadres", value: val(o.customer.email) },
|
|
93
|
+
]);
|
|
94
|
+
const pickupHtml = o.pickupLocations && o.pickupLocations.length > 0
|
|
95
|
+
? o.pickupLocations.map((p) => `<div>${escape(p)}</div>`).join("")
|
|
96
|
+
: `<div style="color:#6b7280;">Onbekend</div>`;
|
|
97
|
+
const notesHtml = o.notes && o.notes.trim()
|
|
98
|
+
? `<div style="background:#fffbeb;border:1px solid #fde68a;border-radius:6px;padding:10px 12px;font-size:13px;white-space:pre-wrap;">${escape(o.notes)}</div>`
|
|
99
|
+
: "";
|
|
100
|
+
return `
|
|
101
|
+
<div style="border:1px solid #e5e7eb;border-radius:8px;padding:16px;margin-bottom:20px;">
|
|
102
|
+
<h3 style="margin:0 0 12px 0;font-size:16px;">Order ${escape(o.orderNumber)}</h3>
|
|
103
|
+
|
|
104
|
+
<div style="margin-bottom:14px;">
|
|
105
|
+
<div style="font-weight:bold;font-size:13px;margin-bottom:6px;color:#111827;">Ordergegevens</div>
|
|
106
|
+
${orderRows}
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<div style="margin-bottom:14px;">
|
|
110
|
+
<div style="font-weight:bold;font-size:13px;margin-bottom:6px;color:#111827;">Klantgegevens</div>
|
|
111
|
+
${customerRows}
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<table style="width:100%;border-collapse:collapse;margin-bottom:14px;">
|
|
115
|
+
<tr>
|
|
116
|
+
<td style="vertical-align:top;width:50%;padding-right:8px;">
|
|
117
|
+
<div style="font-weight:bold;font-size:13px;margin-bottom:6px;color:#111827;">Afleverlocatie</div>
|
|
118
|
+
<div style="font-size:13px;">${renderAddress(o.deliveryLocation)}</div>
|
|
119
|
+
</td>
|
|
120
|
+
<td style="vertical-align:top;width:50%;padding-left:8px;">
|
|
121
|
+
<div style="font-weight:bold;font-size:13px;margin-bottom:6px;color:#111827;">Ophaallocatie</div>
|
|
122
|
+
<div style="font-size:13px;">${pickupHtml}</div>
|
|
123
|
+
</td>
|
|
124
|
+
</tr>
|
|
125
|
+
</table>
|
|
126
|
+
|
|
127
|
+
<div style="margin-bottom:14px;">
|
|
128
|
+
<div style="font-weight:bold;font-size:13px;margin-bottom:6px;color:#111827;">Bestelde artikelen</div>
|
|
129
|
+
${renderItemsTable(o.items)}
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
${notesHtml ? `<div><div style="font-weight:bold;font-size:13px;margin-bottom:6px;color:#111827;">Opmerkingen</div>${notesHtml}</div>` : ""}
|
|
133
|
+
</div>`;
|
|
134
|
+
}
|
|
135
|
+
export function buildCarrierSignupMail(input) {
|
|
136
|
+
const totalCarts = input.orders.reduce((s, o) => s + (o.cartCount ?? 0), 0);
|
|
137
|
+
const totalPlants = input.orders.reduce((s, o) => s + (o.plantCount ?? 0), 0);
|
|
138
|
+
const subject = `Aanmelden karren ${input.carrierName} — ${input.pickupDate.toLocaleDateString("nl-NL", { day: "2-digit", month: "2-digit", year: "numeric" })} ${input.pickupTime}`;
|
|
139
|
+
const summaryRows = input.orders
|
|
140
|
+
.map((o) => `
|
|
141
|
+
<tr>
|
|
142
|
+
<td style="padding:6px 8px;border-bottom:1px solid #e5e7eb;">${escape(o.orderNumber)}</td>
|
|
143
|
+
<td style="padding:6px 8px;border-bottom:1px solid #e5e7eb;">${escape(o.customer.name)}</td>
|
|
144
|
+
<td style="padding:6px 8px;border-bottom:1px solid #e5e7eb;">${escape(o.deliveryType)}</td>
|
|
145
|
+
<td style="padding:6px 8px;border-bottom:1px solid #e5e7eb;text-align:right;">${o.cartCount ?? "—"}</td>
|
|
146
|
+
<td style="padding:6px 8px;border-bottom:1px solid #e5e7eb;text-align:right;">${o.plantCount ?? "—"}</td>
|
|
147
|
+
</tr>`)
|
|
148
|
+
.join("");
|
|
149
|
+
const orderBlocks = input.orders.map(renderOrderBlock).join("");
|
|
150
|
+
const html = `<!doctype html>
|
|
151
|
+
<html lang="nl"><body style="font-family:Arial,sans-serif;color:#111;background:#f9fafb;margin:0;padding:24px;">
|
|
152
|
+
<div style="max-width:760px;margin:0 auto;background:#ffffff;padding:24px;border-radius:8px;">
|
|
153
|
+
<h2 style="margin:0 0 8px 0;">Aanmelden karren — ${escape(input.carrierName)}</h2>
|
|
154
|
+
<p style="margin:0 0 20px 0;color:#374151;font-size:14px;">
|
|
155
|
+
Ophaalmoment: <strong>${escape(fmtDate(input.pickupDate))} om ${escape(input.pickupTime)}</strong><br/>
|
|
156
|
+
Aanmelddeadline: <strong>${escape(fmtDateTime(input.signupDeadline))}</strong>
|
|
157
|
+
</p>
|
|
158
|
+
|
|
159
|
+
<div style="font-weight:bold;font-size:14px;margin-bottom:6px;">Overzicht</div>
|
|
160
|
+
<table style="border-collapse:collapse;width:100%;font-size:13px;margin-bottom:24px;">
|
|
161
|
+
<thead><tr style="background:#f3f4f6;text-align:left;">
|
|
162
|
+
<th style="padding:6px 8px;">Order</th>
|
|
163
|
+
<th style="padding:6px 8px;">Klant</th>
|
|
164
|
+
<th style="padding:6px 8px;">Type</th>
|
|
165
|
+
<th style="padding:6px 8px;text-align:right;">Karren</th>
|
|
166
|
+
<th style="padding:6px 8px;text-align:right;">Planten</th>
|
|
167
|
+
</tr></thead>
|
|
168
|
+
<tbody>${summaryRows}</tbody>
|
|
169
|
+
<tfoot><tr style="font-weight:bold;background:#f9fafb;">
|
|
170
|
+
<td colspan="3" style="padding:6px 8px;text-align:right;">Totaal</td>
|
|
171
|
+
<td style="padding:6px 8px;text-align:right;">${totalCarts}</td>
|
|
172
|
+
<td style="padding:6px 8px;text-align:right;">${totalPlants}</td>
|
|
173
|
+
</tr></tfoot>
|
|
174
|
+
</table>
|
|
175
|
+
|
|
176
|
+
${orderBlocks}
|
|
177
|
+
|
|
178
|
+
<p style="margin-top:16px;font-size:12px;color:#6b7280;">
|
|
179
|
+
Automatisch verzonden door Flowselections Afhandeling.
|
|
180
|
+
</p>
|
|
181
|
+
</div>
|
|
182
|
+
</body></html>`;
|
|
183
|
+
const textOrders = input.orders
|
|
184
|
+
.map((o) => {
|
|
185
|
+
const addr = o.deliveryLocation
|
|
186
|
+
? [
|
|
187
|
+
o.deliveryLocation.name,
|
|
188
|
+
[o.deliveryLocation.street, o.deliveryLocation.houseNumber].filter(Boolean).join(" "),
|
|
189
|
+
[o.deliveryLocation.postalCode, o.deliveryLocation.city].filter(Boolean).join(" "),
|
|
190
|
+
o.deliveryLocation.province,
|
|
191
|
+
o.deliveryLocation.country,
|
|
192
|
+
]
|
|
193
|
+
.filter((v) => v && String(v).trim())
|
|
194
|
+
.join(", ")
|
|
195
|
+
: "Onbekend";
|
|
196
|
+
const items = (o.items ?? [])
|
|
197
|
+
.map((it) => ` - ${it.name}: ${it.quantity ?? "-"} ${it.unit ?? ""}`.trim())
|
|
198
|
+
.join("\n");
|
|
199
|
+
return [
|
|
200
|
+
`Order ${o.orderNumber}`,
|
|
201
|
+
` Besteldatum: ${fmtIsoDate(o.orderDate)}`,
|
|
202
|
+
` Leverdatum: ${fmtIsoDate(o.deliveryDate)}`,
|
|
203
|
+
` Type: ${o.deliveryType}`,
|
|
204
|
+
` Karren: ${o.cartCount ?? "-"} | Planten: ${o.plantCount ?? "-"}`,
|
|
205
|
+
` Klant: ${o.customer.name}` +
|
|
206
|
+
(o.customer.email ? ` <${o.customer.email}>` : ""),
|
|
207
|
+
` Afleverlocatie: ${addr}`,
|
|
208
|
+
` Ophaallocatie: ${(o.pickupLocations ?? []).join(", ") || "Onbekend"}`,
|
|
209
|
+
items ? ` Artikelen:\n${items}` : ` Artikelen: -`,
|
|
210
|
+
o.notes ? ` Opmerkingen: ${o.notes}` : "",
|
|
211
|
+
]
|
|
212
|
+
.filter(Boolean)
|
|
213
|
+
.join("\n");
|
|
214
|
+
})
|
|
215
|
+
.join("\n\n");
|
|
216
|
+
const text = `Aanmelden karren — ${input.carrierName}\n` +
|
|
217
|
+
`Ophaalmoment: ${fmtDate(input.pickupDate)} ${input.pickupTime}\n` +
|
|
218
|
+
`Aanmelddeadline: ${fmtDateTime(input.signupDeadline)}\n\n` +
|
|
219
|
+
textOrders +
|
|
220
|
+
`\n\nTotaal: ${totalCarts} karren, ${totalPlants} planten.`;
|
|
221
|
+
return { subject, html, text, totalCarts, totalPlants };
|
|
222
|
+
}
|
|
223
|
+
function escape(s) {
|
|
224
|
+
return String(s)
|
|
225
|
+
.replace(/&/g, "&")
|
|
226
|
+
.replace(/</g, "<")
|
|
227
|
+
.replace(/>/g, ">")
|
|
228
|
+
.replace(/"/g, """);
|
|
229
|
+
}
|