@shopickup/adapters-foxpost 0.0.1
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/README.md +48 -0
- package/dist/capabilities/index.d.ts +9 -0
- package/dist/capabilities/index.d.ts.map +1 -0
- package/dist/capabilities/index.js +8 -0
- package/dist/capabilities/label.d.ts +27 -0
- package/dist/capabilities/label.d.ts.map +1 -0
- package/dist/capabilities/label.js +370 -0
- package/dist/capabilities/parcels.d.ts +21 -0
- package/dist/capabilities/parcels.d.ts.map +1 -0
- package/dist/capabilities/parcels.js +233 -0
- package/dist/capabilities/pickup-points.d.ts +38 -0
- package/dist/capabilities/pickup-points.d.ts.map +1 -0
- package/dist/capabilities/pickup-points.js +225 -0
- package/dist/capabilities/track.d.ts +16 -0
- package/dist/capabilities/track.d.ts.map +1 -0
- package/dist/capabilities/track.js +99 -0
- package/dist/client/index.d.ts +17 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +30 -0
- package/dist/errors.d.ts +34 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +165 -0
- package/dist/index.d.ts +119 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +151 -0
- package/dist/mappers/index.d.ts +108 -0
- package/dist/mappers/index.d.ts.map +1 -0
- package/dist/mappers/index.js +270 -0
- package/dist/mappers/trackStatus.d.ts +58 -0
- package/dist/mappers/trackStatus.d.ts.map +1 -0
- package/dist/mappers/trackStatus.js +290 -0
- package/dist/types/generated.d.ts +177 -0
- package/dist/types/generated.d.ts.map +1 -0
- package/dist/types/generated.js +9 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/utils/httpUtils.d.ts +18 -0
- package/dist/utils/httpUtils.d.ts.map +1 -0
- package/dist/utils/httpUtils.js +33 -0
- package/dist/utils/resolveBaseUrl.d.ts +23 -0
- package/dist/utils/resolveBaseUrl.d.ts.map +1 -0
- package/dist/utils/resolveBaseUrl.js +19 -0
- package/dist/validation.d.ts +1723 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +799 -0
- package/package.json +68 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mappers for Foxpost adapter
|
|
3
|
+
* Converts between canonical Shopickup types and Foxpost API types
|
|
4
|
+
*/
|
|
5
|
+
import { mapFoxpostStatusCode } from './trackStatus.js';
|
|
6
|
+
const FOXPOST_SIZES = ["xs", "s", "m", "l", "xl"];
|
|
7
|
+
/**
|
|
8
|
+
* Map canonical Address (from Parcel.sender or Parcel.recipient) to Foxpost address format
|
|
9
|
+
*/
|
|
10
|
+
export function mapAddressToFoxpost(addr) {
|
|
11
|
+
return {
|
|
12
|
+
name: addr.name.substring(0, 150), // Foxpost max length
|
|
13
|
+
phone: addr.phone || "",
|
|
14
|
+
email: addr.email || "",
|
|
15
|
+
city: addr.city?.substring(0, 25),
|
|
16
|
+
zip: addr.postalCode,
|
|
17
|
+
address: addr.street?.substring(0, 150),
|
|
18
|
+
country: addr.country || "HU", // Default to Hungary
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Determine parcel size based on dimensions or weight
|
|
23
|
+
* Foxpost sizes: xs, s, m, l, xl
|
|
24
|
+
*/
|
|
25
|
+
export function determineFoxpostSize(parcel) {
|
|
26
|
+
// If no dimensions, default to 's' (small)
|
|
27
|
+
if (!parcel.package.dimensionsCm) {
|
|
28
|
+
return "s";
|
|
29
|
+
}
|
|
30
|
+
const { length, width, height } = parcel.package.dimensionsCm;
|
|
31
|
+
const volume = length * width * height;
|
|
32
|
+
// Very rough heuristic based on volume
|
|
33
|
+
let candidate = "xs";
|
|
34
|
+
if (volume < 5000) {
|
|
35
|
+
candidate = "xs";
|
|
36
|
+
}
|
|
37
|
+
else if (volume < 15000) {
|
|
38
|
+
candidate = "s";
|
|
39
|
+
}
|
|
40
|
+
else if (volume < 50000) {
|
|
41
|
+
candidate = "m";
|
|
42
|
+
}
|
|
43
|
+
else if (volume < 100000) {
|
|
44
|
+
candidate = "l";
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
candidate = "xl";
|
|
48
|
+
}
|
|
49
|
+
return candidate;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Map canonical Parcel to Foxpost CreateParcelRequest (strongly-typed)
|
|
53
|
+
* Returns typed FoxCreateParcelRequestItem with lenient validation support
|
|
54
|
+
*
|
|
55
|
+
* Handles both HOME delivery (full address) and PICKUP_POINT delivery (APM/locker)
|
|
56
|
+
*/
|
|
57
|
+
export function mapParcelToFoxpostRequest(parcel, options = {}) {
|
|
58
|
+
const delivery = parcel.recipient.delivery;
|
|
59
|
+
const isHomeDelivery = delivery.method === 'HOME';
|
|
60
|
+
const recipientAddr = isHomeDelivery
|
|
61
|
+
? delivery.address
|
|
62
|
+
: undefined;
|
|
63
|
+
const recipient = {
|
|
64
|
+
name: parcel.recipient.contact.name.substring(0, 150),
|
|
65
|
+
phone: parcel.recipient.contact.phone || "",
|
|
66
|
+
email: parcel.recipient.contact.email || "",
|
|
67
|
+
city: recipientAddr?.city?.substring(0, 25),
|
|
68
|
+
zip: recipientAddr?.postalCode,
|
|
69
|
+
address: recipientAddr?.street?.substring(0, 150),
|
|
70
|
+
country: recipientAddr?.country || "HU",
|
|
71
|
+
};
|
|
72
|
+
// COD amount from parcel if present, default to 0
|
|
73
|
+
const codAmount = parcel.cod?.amount.amount ?? 0;
|
|
74
|
+
const baseRequest = {
|
|
75
|
+
recipientName: recipient.name,
|
|
76
|
+
recipientPhone: recipient.phone,
|
|
77
|
+
recipientEmail: recipient.email,
|
|
78
|
+
size: determineFoxpostSize(parcel)?.toUpperCase() || 'S',
|
|
79
|
+
cod: codAmount,
|
|
80
|
+
// Optional fields
|
|
81
|
+
refCode: parcel.references?.customerReference
|
|
82
|
+
?.substring(0, 30)
|
|
83
|
+
.concat(`-${parcel.id.substring(0, 10)}`),
|
|
84
|
+
comment: parcel.handling?.fragile ? 'FRAGILE' : undefined,
|
|
85
|
+
fragile: parcel.handling?.fragile || false,
|
|
86
|
+
};
|
|
87
|
+
// HOME delivery includes address fields
|
|
88
|
+
if (isHomeDelivery) {
|
|
89
|
+
return {
|
|
90
|
+
...baseRequest,
|
|
91
|
+
recipientCity: recipient.city,
|
|
92
|
+
recipientZip: recipient.zip,
|
|
93
|
+
recipientAddress: recipient.address,
|
|
94
|
+
recipientCountry: recipient.country,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// PICKUP_POINT delivery adds destination (locker/APM code)
|
|
98
|
+
if (delivery.method === 'PICKUP_POINT') {
|
|
99
|
+
const pickupPoint = delivery.pickupPoint;
|
|
100
|
+
return {
|
|
101
|
+
...baseRequest,
|
|
102
|
+
destination: pickupPoint?.id || '',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return baseRequest;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Map canonical Parcel to Foxpost CreateParcelRequest
|
|
109
|
+
* Parcel contains complete shipping details (sender, recipient, weight, service, etc.)
|
|
110
|
+
*
|
|
111
|
+
* Handles both HOME delivery (full address) and PICKUP_POINT delivery (APM/locker)
|
|
112
|
+
*/
|
|
113
|
+
export function mapParcelToFoxpost(parcel, options = {}) {
|
|
114
|
+
const delivery = parcel.recipient.delivery;
|
|
115
|
+
const isHomeDelivery = delivery.method === 'HOME';
|
|
116
|
+
const recipientAddr = isHomeDelivery
|
|
117
|
+
? delivery.address
|
|
118
|
+
: undefined;
|
|
119
|
+
const recipient = {
|
|
120
|
+
name: parcel.recipient.contact.name.substring(0, 150),
|
|
121
|
+
phone: parcel.recipient.contact.phone || "",
|
|
122
|
+
email: parcel.recipient.contact.email || "",
|
|
123
|
+
city: recipientAddr?.city?.substring(0, 25),
|
|
124
|
+
zip: recipientAddr?.postalCode,
|
|
125
|
+
address: recipientAddr?.street?.substring(0, 150),
|
|
126
|
+
country: recipientAddr?.country || "HU",
|
|
127
|
+
};
|
|
128
|
+
const foxpostRequest = {
|
|
129
|
+
recipientName: recipient.name,
|
|
130
|
+
recipientPhone: recipient.phone,
|
|
131
|
+
recipientEmail: recipient.email,
|
|
132
|
+
// HOME delivery includes address fields; APM leaves them undefined
|
|
133
|
+
...(isHomeDelivery && {
|
|
134
|
+
recipientCity: recipient.city,
|
|
135
|
+
recipientZip: recipient.zip,
|
|
136
|
+
recipientAddress: recipient.address,
|
|
137
|
+
recipientCountry: recipient.country,
|
|
138
|
+
}),
|
|
139
|
+
size: determineFoxpostSize(parcel),
|
|
140
|
+
// Optional fields
|
|
141
|
+
refCode: parcel.references?.customerReference
|
|
142
|
+
?.substring(0, 30)
|
|
143
|
+
.concat(`-${parcel.id.substring(0, 10)}`),
|
|
144
|
+
comment: parcel.handling?.fragile ? 'FRAGILE' : undefined,
|
|
145
|
+
fragile: parcel.handling?.fragile || false,
|
|
146
|
+
};
|
|
147
|
+
// For PICKUP_POINT delivery, add destination (locker/APM code)
|
|
148
|
+
if (!isHomeDelivery && delivery.method === 'PICKUP_POINT') {
|
|
149
|
+
const pickupPoint = delivery.pickupPoint;
|
|
150
|
+
if (pickupPoint?.id) {
|
|
151
|
+
foxpostRequest.destination = pickupPoint.id;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return foxpostRequest;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Map Foxpost tracking status code to canonical TrackingStatus
|
|
158
|
+
* Uses comprehensive status mapping from trackStatus.ts
|
|
159
|
+
* Unknown codes default to PENDING.
|
|
160
|
+
*/
|
|
161
|
+
export function mapFoxpostStatusToCanonical(foxpostStatus) {
|
|
162
|
+
const mapping = mapFoxpostStatusCode(foxpostStatus);
|
|
163
|
+
return mapping.canonical; // Safe cast: trackStatus map returns valid canonical values
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Map Foxpost TrackDTO to canonical TrackingEvent
|
|
167
|
+
*
|
|
168
|
+
* Normalizes the Foxpost status code to a canonical TrackingStatus while preserving
|
|
169
|
+
* the original carrier-specific code in `carrierStatusCode` for debugging and carrier-specific logic.
|
|
170
|
+
*/
|
|
171
|
+
export function mapFoxpostTrackToCanonical(track) {
|
|
172
|
+
return {
|
|
173
|
+
timestamp: new Date(track.statusDate || new Date()),
|
|
174
|
+
status: mapFoxpostStatusToCanonical(track.status || "PENDING"),
|
|
175
|
+
carrierStatusCode: track.status || undefined,
|
|
176
|
+
description: track.longName || track.status || "Unknown status",
|
|
177
|
+
raw: track,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Map Foxpost TraceDTO (from new /api/tracking/{barcode} endpoint) to canonical TrackingEvent
|
|
182
|
+
* TraceDTO is returned in reverse chronological order (latest first) from the API
|
|
183
|
+
*
|
|
184
|
+
* Normalizes the Foxpost status code to a canonical TrackingStatus while preserving
|
|
185
|
+
* the original carrier-specific code in `carrierStatusCode`.
|
|
186
|
+
*
|
|
187
|
+
* Includes both English and Hungarian human-readable descriptions from the status map.
|
|
188
|
+
*
|
|
189
|
+
* Accepts both string and Date types for statusDate to support both raw API responses
|
|
190
|
+
* and validated Zod-parsed responses (which transform to Date).
|
|
191
|
+
*
|
|
192
|
+
* Example mapping:
|
|
193
|
+
* - Foxpost "CREATE" -> canonical "PENDING" (carrierStatusCode: "CREATE", description: "Order created")
|
|
194
|
+
* - Foxpost "HDINTRANSIT" -> canonical "OUT_FOR_DELIVERY" (carrierStatusCode: "HDINTRANSIT", description: "Out for home delivery")
|
|
195
|
+
* - Foxpost "RECEIVE" -> canonical "DELIVERED" (carrierStatusCode: "RECEIVE", description: "Delivered to recipient")
|
|
196
|
+
*/
|
|
197
|
+
export function mapFoxpostTraceToCanonical(trace) {
|
|
198
|
+
const statusDate = typeof trace.statusDate === 'string'
|
|
199
|
+
? new Date(trace.statusDate)
|
|
200
|
+
: trace.statusDate;
|
|
201
|
+
const statusCode = trace.status || "PENDING";
|
|
202
|
+
const statusMapping = mapFoxpostStatusCode(statusCode);
|
|
203
|
+
// Prefer mapped human description; fall back to API data if available
|
|
204
|
+
const humanDescription = statusMapping.human_en
|
|
205
|
+
|| (trace.longName || trace.shortName || null)
|
|
206
|
+
|| `Foxpost: ${statusCode}`;
|
|
207
|
+
const humanDescriptionHu = statusMapping.human_hu || null;
|
|
208
|
+
return {
|
|
209
|
+
timestamp: statusDate || new Date(),
|
|
210
|
+
status: mapFoxpostStatusToCanonical(statusCode),
|
|
211
|
+
carrierStatusCode: statusCode || undefined,
|
|
212
|
+
description: humanDescription,
|
|
213
|
+
descriptionLocalLanguage: humanDescriptionHu || undefined,
|
|
214
|
+
raw: trace,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Map canonical Parcel to Foxpost carrier-specific parcel (HD or APM)
|
|
219
|
+
* Discriminates based on Delivery type in the parcel
|
|
220
|
+
*
|
|
221
|
+
* @param parcel - Canonical parcel with full shipping details
|
|
222
|
+
* @param options - Additional mapping options (COD, comment, etc.)
|
|
223
|
+
* @returns FoxpostParcelHD | FoxpostParcelAPM with type discriminator set
|
|
224
|
+
*/
|
|
225
|
+
export function mapParcelToFoxpostCarrierType(parcel, options = {}) {
|
|
226
|
+
const recipient = parcel.recipient;
|
|
227
|
+
const delivery = recipient.delivery;
|
|
228
|
+
// Determine parcel size
|
|
229
|
+
const size = (determineFoxpostSize(parcel) || 's').toUpperCase();
|
|
230
|
+
// COD amount from parcel.cod or options override
|
|
231
|
+
const codAmount = options.cod ?? parcel.cod?.amount.amount ?? 0;
|
|
232
|
+
// Fragile from options or parcel.handling
|
|
233
|
+
const isFragile = options.fragile ?? parcel.handling?.fragile ?? false;
|
|
234
|
+
// If delivery is PICKUP_POINT, create APM parcel
|
|
235
|
+
if (delivery.method === 'PICKUP_POINT') {
|
|
236
|
+
const apmParcel = {
|
|
237
|
+
type: 'APM',
|
|
238
|
+
cod: codAmount,
|
|
239
|
+
comment: options.comment,
|
|
240
|
+
destination: delivery.pickupPoint.id,
|
|
241
|
+
recipientEmail: recipient.contact.email || '',
|
|
242
|
+
recipientName: recipient.contact.name.substring(0, 150),
|
|
243
|
+
recipientPhone: recipient.contact.phone || '',
|
|
244
|
+
refCode: parcel.references?.customerReference?.substring(0, 30),
|
|
245
|
+
size,
|
|
246
|
+
};
|
|
247
|
+
return apmParcel;
|
|
248
|
+
}
|
|
249
|
+
// Otherwise (HOME delivery), create HD parcel
|
|
250
|
+
const homeDelivery = delivery;
|
|
251
|
+
const recipientAddr = homeDelivery.address;
|
|
252
|
+
const hdParcel = {
|
|
253
|
+
type: 'HD',
|
|
254
|
+
cod: codAmount,
|
|
255
|
+
comment: options.comment,
|
|
256
|
+
deliveryNote: options.deliveryNote || homeDelivery.instructions,
|
|
257
|
+
fragile: isFragile,
|
|
258
|
+
label: false, // Default: Foxpost prints label for B2B, not for C2C
|
|
259
|
+
recipientAddress: `${recipientAddr.street || ''}, ${recipientAddr.postalCode || ''} ${recipientAddr.city || ''}`.trim(),
|
|
260
|
+
recipientCity: recipientAddr.city,
|
|
261
|
+
recipientCountry: recipientAddr.country,
|
|
262
|
+
recipientEmail: recipient.contact.email || '',
|
|
263
|
+
recipientName: recipient.contact.name.substring(0, 150),
|
|
264
|
+
recipientPhone: recipient.contact.phone || '',
|
|
265
|
+
recipientZip: recipientAddr.postalCode,
|
|
266
|
+
refCode: parcel.references?.customerReference?.substring(0, 30),
|
|
267
|
+
size,
|
|
268
|
+
};
|
|
269
|
+
return hdParcel;
|
|
270
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Foxpost Tracking Status Map
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive mapping of Foxpost status codes to:
|
|
5
|
+
* 1. Canonical tracking status (for normalized processing)
|
|
6
|
+
* 2. Human-readable descriptions in English and Hungarian
|
|
7
|
+
*
|
|
8
|
+
* The canonical status is used for generic processing, filtering, and integrator logic,
|
|
9
|
+
* while the human descriptions provide detailed information about the shipment state.
|
|
10
|
+
*
|
|
11
|
+
* Source: Foxpost OpenAPI tracking documentation and operational codes
|
|
12
|
+
*/
|
|
13
|
+
import type { TrackingStatus } from "@shopickup/core";
|
|
14
|
+
export interface FoxpostStatusMapping {
|
|
15
|
+
/** Canonical status across all carriers */
|
|
16
|
+
canonical: TrackingStatus;
|
|
17
|
+
/** Human-readable description in English */
|
|
18
|
+
human_en?: string;
|
|
19
|
+
/** Human-readable description in Hungarian */
|
|
20
|
+
human_hu?: string;
|
|
21
|
+
/** Category hint for interpretation */
|
|
22
|
+
type?: 'locker' | 'courier' | 'facility' | 'technical';
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Complete Foxpost status code to canonical mapping
|
|
26
|
+
*
|
|
27
|
+
* Key characteristics:
|
|
28
|
+
* - All Foxpost codes are covered (37 codes)
|
|
29
|
+
* - Unknown codes default to "UNKNOWN" with fallback description
|
|
30
|
+
* - Each code has English and Hungarian descriptions from Foxpost docs
|
|
31
|
+
* - Technical codes (CREATE, SLOTCHANGE, etc.) are marked with type: 'technical'
|
|
32
|
+
*/
|
|
33
|
+
export declare const FOXPOST_STATUS_MAP: Record<string, FoxpostStatusMapping>;
|
|
34
|
+
/**
|
|
35
|
+
* Map Foxpost status code to canonical and human descriptions
|
|
36
|
+
*
|
|
37
|
+
* @param code Foxpost status code (e.g., "OPERIN", "HDINTRANSIT")
|
|
38
|
+
* @returns Mapping with canonical status and human descriptions (EN + HU)
|
|
39
|
+
*
|
|
40
|
+
* Unknown codes default to PENDING canonical status with fallback description.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const mapping = mapFoxpostStatusCode("OPERIN");
|
|
44
|
+
* // { canonical: "IN_TRANSIT", human_en: "Arrived at locker", human_hu: "Automatában megérkezett" }
|
|
45
|
+
*
|
|
46
|
+
* const unknown = mapFoxpostStatusCode("FOOBAR");
|
|
47
|
+
* // { canonical: "PENDING", human_en: "Foxpost: FOOBAR", human_hu: undefined }
|
|
48
|
+
*/
|
|
49
|
+
export declare function mapFoxpostStatusCode(code: string): FoxpostStatusMapping;
|
|
50
|
+
/**
|
|
51
|
+
* Get human-readable description in specified language
|
|
52
|
+
*
|
|
53
|
+
* @param code Foxpost status code
|
|
54
|
+
* @param language "en" for English, "hu" for Hungarian
|
|
55
|
+
* @returns Human-readable description
|
|
56
|
+
*/
|
|
57
|
+
export declare function getFoxpostStatusDescription(code: string, language?: "en" | "hu"): string;
|
|
58
|
+
//# sourceMappingURL=trackStatus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trackStatus.d.ts","sourceRoot":"","sources":["../../src/mappers/trackStatus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,WAAW,oBAAoB;IACnC,2CAA2C;IAC3C,SAAS,EAAE,cAAc,CAAC;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;CACxD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CA0OnE,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,CAcvE;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,IAAI,GAAG,IAAW,GAC3B,MAAM,CAQR"}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Foxpost Tracking Status Map
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive mapping of Foxpost status codes to:
|
|
5
|
+
* 1. Canonical tracking status (for normalized processing)
|
|
6
|
+
* 2. Human-readable descriptions in English and Hungarian
|
|
7
|
+
*
|
|
8
|
+
* The canonical status is used for generic processing, filtering, and integrator logic,
|
|
9
|
+
* while the human descriptions provide detailed information about the shipment state.
|
|
10
|
+
*
|
|
11
|
+
* Source: Foxpost OpenAPI tracking documentation and operational codes
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Complete Foxpost status code to canonical mapping
|
|
15
|
+
*
|
|
16
|
+
* Key characteristics:
|
|
17
|
+
* - All Foxpost codes are covered (37 codes)
|
|
18
|
+
* - Unknown codes default to "UNKNOWN" with fallback description
|
|
19
|
+
* - Each code has English and Hungarian descriptions from Foxpost docs
|
|
20
|
+
* - Technical codes (CREATE, SLOTCHANGE, etc.) are marked with type: 'technical'
|
|
21
|
+
*/
|
|
22
|
+
export const FOXPOST_STATUS_MAP = {
|
|
23
|
+
// === Locker/APM Operations ===
|
|
24
|
+
CREATE: {
|
|
25
|
+
canonical: "PENDING",
|
|
26
|
+
human_en: "Order created",
|
|
27
|
+
human_hu: "Rendelés létrehozva",
|
|
28
|
+
type: "locker",
|
|
29
|
+
},
|
|
30
|
+
OPERIN: {
|
|
31
|
+
canonical: "IN_TRANSIT",
|
|
32
|
+
human_en: "Arrived at locker",
|
|
33
|
+
human_hu: "Automatában megérkezett",
|
|
34
|
+
type: "locker",
|
|
35
|
+
},
|
|
36
|
+
OPEROUT: {
|
|
37
|
+
canonical: "IN_TRANSIT",
|
|
38
|
+
human_en: "Removed from locker / Out for delivery",
|
|
39
|
+
human_hu: "Automatából kivéve / Kiszállítás",
|
|
40
|
+
type: "locker",
|
|
41
|
+
},
|
|
42
|
+
RECEIVE: {
|
|
43
|
+
canonical: "DELIVERED",
|
|
44
|
+
human_en: "Delivered to recipient",
|
|
45
|
+
human_hu: "Átvéve",
|
|
46
|
+
type: "locker",
|
|
47
|
+
},
|
|
48
|
+
// === Return Operations ===
|
|
49
|
+
RETURN: {
|
|
50
|
+
canonical: "RETURNED",
|
|
51
|
+
human_en: "Returned to sender",
|
|
52
|
+
human_hu: "Visszaküldésre került",
|
|
53
|
+
type: "facility",
|
|
54
|
+
},
|
|
55
|
+
REDIRECT: {
|
|
56
|
+
canonical: "IN_TRANSIT",
|
|
57
|
+
human_en: "Redirected to new destination",
|
|
58
|
+
human_hu: "Átirányítva új célhelyre",
|
|
59
|
+
type: "facility",
|
|
60
|
+
},
|
|
61
|
+
BACKTOSENDER: {
|
|
62
|
+
canonical: "RETURNED",
|
|
63
|
+
human_en: "Returned to sender",
|
|
64
|
+
human_hu: "Szállító felé visszaküldve",
|
|
65
|
+
type: "facility",
|
|
66
|
+
},
|
|
67
|
+
RESENT: {
|
|
68
|
+
canonical: "IN_TRANSIT",
|
|
69
|
+
human_en: "Resent to new destination",
|
|
70
|
+
human_hu: "Újra küldve új célhelyre",
|
|
71
|
+
type: "facility",
|
|
72
|
+
},
|
|
73
|
+
// === Facility Sorting Operations ===
|
|
74
|
+
SORTIN: {
|
|
75
|
+
canonical: "IN_TRANSIT",
|
|
76
|
+
human_en: "Arrived at sorting facility",
|
|
77
|
+
human_hu: "Rendezőközpontba megérkezett",
|
|
78
|
+
type: "facility",
|
|
79
|
+
},
|
|
80
|
+
SORTOUT: {
|
|
81
|
+
canonical: "IN_TRANSIT",
|
|
82
|
+
human_en: "Left sorting facility",
|
|
83
|
+
human_hu: "Rendezőközpontból elküldve",
|
|
84
|
+
type: "facility",
|
|
85
|
+
},
|
|
86
|
+
MPSIN: {
|
|
87
|
+
canonical: "IN_TRANSIT",
|
|
88
|
+
human_en: "Arrived at parcel hub",
|
|
89
|
+
human_hu: "Csomagközpontba megérkezett",
|
|
90
|
+
type: "facility",
|
|
91
|
+
},
|
|
92
|
+
C2CIN: {
|
|
93
|
+
canonical: "IN_TRANSIT",
|
|
94
|
+
human_en: "Arrived at customer collection point",
|
|
95
|
+
human_hu: "Ügyfél felvevőpontba megérkezett",
|
|
96
|
+
type: "facility",
|
|
97
|
+
},
|
|
98
|
+
C2BIN: {
|
|
99
|
+
canonical: "IN_TRANSIT",
|
|
100
|
+
human_en: "Arrived at business collection point",
|
|
101
|
+
human_hu: "Üzleti felvevőpontba megérkezett",
|
|
102
|
+
type: "facility",
|
|
103
|
+
},
|
|
104
|
+
INWAREHOUSE: {
|
|
105
|
+
canonical: "IN_TRANSIT",
|
|
106
|
+
human_en: "In warehouse",
|
|
107
|
+
human_hu: "Raktárban van",
|
|
108
|
+
type: "facility",
|
|
109
|
+
},
|
|
110
|
+
// === Home Delivery Operations ===
|
|
111
|
+
HDSENT: {
|
|
112
|
+
canonical: "OUT_FOR_DELIVERY",
|
|
113
|
+
human_en: "Home delivery sent",
|
|
114
|
+
human_hu: "Házhozszállítás küldve",
|
|
115
|
+
type: "courier",
|
|
116
|
+
},
|
|
117
|
+
HDINTRANSIT: {
|
|
118
|
+
canonical: "OUT_FOR_DELIVERY",
|
|
119
|
+
human_en: "Out for home delivery",
|
|
120
|
+
human_hu: "Házhoz szállítás alatt",
|
|
121
|
+
type: "courier",
|
|
122
|
+
},
|
|
123
|
+
HDDEPO: {
|
|
124
|
+
canonical: "IN_TRANSIT",
|
|
125
|
+
human_en: "At home delivery depot",
|
|
126
|
+
human_hu: "Kiszállítási depoban",
|
|
127
|
+
type: "facility",
|
|
128
|
+
},
|
|
129
|
+
HDCOURIER: {
|
|
130
|
+
canonical: "OUT_FOR_DELIVERY",
|
|
131
|
+
human_en: "With courier for delivery",
|
|
132
|
+
human_hu: "Futárnál szállításra",
|
|
133
|
+
type: "courier",
|
|
134
|
+
},
|
|
135
|
+
HDHUBIN: {
|
|
136
|
+
canonical: "IN_TRANSIT",
|
|
137
|
+
human_en: "Arrived at delivery hub",
|
|
138
|
+
human_hu: "Szállítási csomópontra megérkezett",
|
|
139
|
+
type: "facility",
|
|
140
|
+
},
|
|
141
|
+
HDHUBOUT: {
|
|
142
|
+
canonical: "OUT_FOR_DELIVERY",
|
|
143
|
+
human_en: "Left delivery hub",
|
|
144
|
+
human_hu: "Szállítási csomópontból elküldve",
|
|
145
|
+
type: "facility",
|
|
146
|
+
},
|
|
147
|
+
HDRECEIVE: {
|
|
148
|
+
canonical: "DELIVERED",
|
|
149
|
+
human_en: "Delivered by home delivery",
|
|
150
|
+
human_hu: "Házhoz szállítva",
|
|
151
|
+
type: "courier",
|
|
152
|
+
},
|
|
153
|
+
HDRETURN: {
|
|
154
|
+
canonical: "RETURNED",
|
|
155
|
+
human_en: "Returned from home delivery",
|
|
156
|
+
human_hu: "Házhoz szállítás visszatérült",
|
|
157
|
+
type: "courier",
|
|
158
|
+
},
|
|
159
|
+
// === Exception States ===
|
|
160
|
+
OVERTIMEOUT: {
|
|
161
|
+
canonical: "EXCEPTION",
|
|
162
|
+
human_en: "Overtime out (delivery exceeded time limit)",
|
|
163
|
+
human_hu: "Túlóra lejárt",
|
|
164
|
+
type: "technical",
|
|
165
|
+
},
|
|
166
|
+
OVERTIMED: {
|
|
167
|
+
canonical: "EXCEPTION",
|
|
168
|
+
human_en: "Overtime (delivery delayed)",
|
|
169
|
+
human_hu: "Túlóra (késedelem)",
|
|
170
|
+
type: "technical",
|
|
171
|
+
},
|
|
172
|
+
HDUNDELIVERABLE: {
|
|
173
|
+
canonical: "EXCEPTION",
|
|
174
|
+
human_en: "Undeliverable (home delivery failed)",
|
|
175
|
+
human_hu: "Nem szállítható (házhoz szállítás sikertelen)",
|
|
176
|
+
type: "courier",
|
|
177
|
+
},
|
|
178
|
+
MISSORT: {
|
|
179
|
+
canonical: "EXCEPTION",
|
|
180
|
+
human_en: "Missorted - rerouted",
|
|
181
|
+
human_hu: "Hibásan rendezett - átirányított",
|
|
182
|
+
type: "technical",
|
|
183
|
+
},
|
|
184
|
+
EMPTYSLOT: {
|
|
185
|
+
canonical: "EXCEPTION",
|
|
186
|
+
human_en: "No locker slot available",
|
|
187
|
+
human_hu: "Nincs szabad automatahely",
|
|
188
|
+
type: "locker",
|
|
189
|
+
},
|
|
190
|
+
BACKLOGINFULL: {
|
|
191
|
+
canonical: "EXCEPTION",
|
|
192
|
+
human_en: "Backlog - facility at capacity",
|
|
193
|
+
human_hu: "Feldolgozási várakozási sor teljes",
|
|
194
|
+
type: "facility",
|
|
195
|
+
},
|
|
196
|
+
BACKLOGINFAIL: {
|
|
197
|
+
canonical: "EXCEPTION",
|
|
198
|
+
human_en: "Backlog failed - retry needed",
|
|
199
|
+
human_hu: "Feldolgozási sor sikertelen",
|
|
200
|
+
type: "technical",
|
|
201
|
+
},
|
|
202
|
+
// === Collection/Handoff Operations ===
|
|
203
|
+
COLLECTSENT: {
|
|
204
|
+
canonical: "IN_TRANSIT",
|
|
205
|
+
human_en: "Collect shipment sent",
|
|
206
|
+
human_hu: "Gyűjtőszállítmány küldve",
|
|
207
|
+
type: "facility",
|
|
208
|
+
},
|
|
209
|
+
COLLECTED: {
|
|
210
|
+
canonical: "DELIVERED",
|
|
211
|
+
human_en: "Collected from sender",
|
|
212
|
+
human_hu: "Feladótól összeszedve",
|
|
213
|
+
type: "facility",
|
|
214
|
+
},
|
|
215
|
+
// === Slot/Redirect Operations ===
|
|
216
|
+
SLOTCHANGE: {
|
|
217
|
+
canonical: "IN_TRANSIT",
|
|
218
|
+
human_en: "Locker slot changed",
|
|
219
|
+
human_hu: "Automatahely módosult",
|
|
220
|
+
type: "technical",
|
|
221
|
+
},
|
|
222
|
+
WBXREDIRECT: {
|
|
223
|
+
canonical: "IN_TRANSIT",
|
|
224
|
+
human_en: "Redirected via WBX",
|
|
225
|
+
human_hu: "WBX-en keresztül átirányított",
|
|
226
|
+
type: "facility",
|
|
227
|
+
},
|
|
228
|
+
PREREDIRECT: {
|
|
229
|
+
canonical: "IN_TRANSIT",
|
|
230
|
+
human_en: "Pre-redirect (staged for redirection)",
|
|
231
|
+
human_hu: "Előátirányítás (átirányításra előkészítve)",
|
|
232
|
+
type: "technical",
|
|
233
|
+
},
|
|
234
|
+
// === Final Delivery State ===
|
|
235
|
+
RETURNED: {
|
|
236
|
+
canonical: "DELIVERED",
|
|
237
|
+
human_en: "Returned (delivered back to sender)",
|
|
238
|
+
human_hu: "Visszaküldve (feladónak szállítva)",
|
|
239
|
+
type: "facility",
|
|
240
|
+
},
|
|
241
|
+
// === Preparation/Technical ===
|
|
242
|
+
PREPAREDFORPD: {
|
|
243
|
+
canonical: "IN_TRANSIT",
|
|
244
|
+
human_en: "Prepared for home delivery",
|
|
245
|
+
human_hu: "Házhoz szállításra előkészítve",
|
|
246
|
+
type: "technical",
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
/**
|
|
250
|
+
* Map Foxpost status code to canonical and human descriptions
|
|
251
|
+
*
|
|
252
|
+
* @param code Foxpost status code (e.g., "OPERIN", "HDINTRANSIT")
|
|
253
|
+
* @returns Mapping with canonical status and human descriptions (EN + HU)
|
|
254
|
+
*
|
|
255
|
+
* Unknown codes default to PENDING canonical status with fallback description.
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* const mapping = mapFoxpostStatusCode("OPERIN");
|
|
259
|
+
* // { canonical: "IN_TRANSIT", human_en: "Arrived at locker", human_hu: "Automatában megérkezett" }
|
|
260
|
+
*
|
|
261
|
+
* const unknown = mapFoxpostStatusCode("FOOBAR");
|
|
262
|
+
* // { canonical: "PENDING", human_en: "Foxpost: FOOBAR", human_hu: undefined }
|
|
263
|
+
*/
|
|
264
|
+
export function mapFoxpostStatusCode(code) {
|
|
265
|
+
const mapping = FOXPOST_STATUS_MAP[code];
|
|
266
|
+
if (mapping) {
|
|
267
|
+
return mapping;
|
|
268
|
+
}
|
|
269
|
+
// Fallback for unknown codes: map to PENDING with fallback description
|
|
270
|
+
return {
|
|
271
|
+
canonical: "PENDING",
|
|
272
|
+
human_en: `Foxpost: ${code}`,
|
|
273
|
+
human_hu: undefined,
|
|
274
|
+
type: "technical",
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Get human-readable description in specified language
|
|
279
|
+
*
|
|
280
|
+
* @param code Foxpost status code
|
|
281
|
+
* @param language "en" for English, "hu" for Hungarian
|
|
282
|
+
* @returns Human-readable description
|
|
283
|
+
*/
|
|
284
|
+
export function getFoxpostStatusDescription(code, language = "en") {
|
|
285
|
+
const mapping = mapFoxpostStatusCode(code);
|
|
286
|
+
if (language === "hu") {
|
|
287
|
+
return mapping.human_hu ?? mapping.human_en ?? `Foxpost: ${code}`;
|
|
288
|
+
}
|
|
289
|
+
return mapping.human_en ?? `Foxpost: ${code}`;
|
|
290
|
+
}
|