@pvh-afl/graphql 1.0.23 → 1.0.25

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.
@@ -1,35 +1,57 @@
1
- import { IntegrationFactory, ConfigService } from '@pvh-afl/core';
1
+ import { ConfigService } from '@pvh-afl/core';
2
2
  import { OrderTrackingInput, OrderTrackingResult } from './order-tracking.types';
3
3
  /**
4
4
  * Order Tracking Service
5
5
  *
6
- * Combines data from Omuni OMS and Shopify Admin API for unified tracking.
6
+ * Fetches comprehensive order tracking data from Shopify Admin API.
7
7
  */
8
8
  export declare class OrderTrackingService {
9
- private readonly integrationFactory;
10
9
  private readonly configService;
11
- private readonly SHOPIFY_API_VERSION;
12
- constructor(integrationFactory: IntegrationFactory, configService: ConfigService);
10
+ constructor(configService: ConfigService);
13
11
  /**
14
- * Get unified order tracking information from Omuni and Shopify.
12
+ * Get complete order tracking information from Shopify.
15
13
  */
16
14
  getOrderTracking(brand: string, input: OrderTrackingInput): Promise<OrderTrackingResult>;
17
15
  /**
18
- * Fetch order tracking data from Omuni OMS.
16
+ * Fetch complete order details from Shopify Admin API.
19
17
  */
20
- private fetchFromOmuni;
18
+ private fetchFromShopify;
21
19
  /**
22
- * Fetch order details and fulfillment events from Shopify Admin API.
20
+ * Get tracking URL from fulfillment.
23
21
  */
24
- private fetchFromShopify;
22
+ private getTrackingUrl;
25
23
  /**
26
24
  * Map Shopify order to OrderDetails type.
27
25
  */
28
26
  private mapOrderDetails;
27
+ /**
28
+ * Map line items from Shopify order.
29
+ */
30
+ private mapLineItems;
31
+ /**
32
+ * Map cancellation info if order was cancelled.
33
+ */
34
+ private mapCancellation;
35
+ /**
36
+ * Map returns from Shopify order.
37
+ */
38
+ private mapReturns;
39
+ /**
40
+ * Map refunds from Shopify order.
41
+ */
42
+ private mapRefunds;
29
43
  /**
30
44
  * Build tracking timeline from Shopify fulfillment events.
31
45
  */
32
46
  private buildTrackingTimeline;
47
+ /**
48
+ * Map Shopify money to OrderMoney type.
49
+ */
50
+ private mapMoney;
51
+ /**
52
+ * Map Shopify address to OrderAddress type.
53
+ */
54
+ private mapAddress;
33
55
  /**
34
56
  * Format payment gateway names to readable format.
35
57
  */
@@ -1 +1 @@
1
- {"version":3,"file":"order-tracking.service.d.ts","sourceRoot":"","sources":["../../src/order-tracking/order-tracking.service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAGlB,aAAa,EAEd,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EAIpB,MAAM,wBAAwB,CAAC;AAwDhC;;;;GAIG;AACH,qBACa,oBAAoB;IAI7B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAJhC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAa;gBAG9B,kBAAkB,EAAE,kBAAkB,EACtC,aAAa,EAAE,aAAa;IAG/C;;OAEG;IACG,gBAAgB,CACpB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC;IAqB/B;;OAEG;YACW,cAAc;IA2D5B;;OAEG;YACW,gBAAgB;IAqH9B;;OAEG;IACH,OAAO,CAAC,eAAe;IAmCvB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAyF7B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA6B3B;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,OAAO,CAAC,qBAAqB;CAiB9B"}
1
+ {"version":3,"file":"order-tracking.service.d.ts","sourceRoot":"","sources":["../../src/order-tracking/order-tracking.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAU,MAAM,eAAe,CAAC;AACtD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EAWpB,MAAM,wBAAwB,CAAC;AAiJhC;;;;GAIG;AACH,qBACa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa;IAEzD;;OAEG;IACG,gBAAgB,CACpB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC;IAkB/B;;OAEG;YACW,gBAAgB;IAmJ9B;;OAEG;IACH,OAAO,CAAC,cAAc;IAKtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAiEvB;;OAEG;IACH,OAAO,CAAC,YAAY;IAsBpB;;OAEG;IACH,OAAO,CAAC,eAAe;IA4BvB;;OAEG;IACH,OAAO,CAAC,UAAU;IAyBlB;;OAEG;IACH,OAAO,CAAC,UAAU;IAalB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAwF7B;;OAEG;IACH,OAAO,CAAC,QAAQ;IAOhB;;OAEG;IACH,OAAO,CAAC,UAAU;IAiBlB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,OAAO,CAAC,qBAAqB;CAiB9B"}
@@ -4,93 +4,43 @@ exports.OrderTrackingService = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const common_1 = require("@nestjs/common");
6
6
  const core_1 = require("@pvh-afl/core");
7
+ // Cancellation window in minutes
8
+ const CANCELLATION_WINDOW_MINUTES = 30;
7
9
  /**
8
10
  * Order Tracking Service
9
11
  *
10
- * Combines data from Omuni OMS and Shopify Admin API for unified tracking.
12
+ * Fetches comprehensive order tracking data from Shopify Admin API.
11
13
  */
12
14
  let OrderTrackingService = class OrderTrackingService {
13
- integrationFactory;
14
15
  configService;
15
- SHOPIFY_API_VERSION = '2024-01';
16
- constructor(integrationFactory, configService) {
17
- this.integrationFactory = integrationFactory;
16
+ constructor(configService) {
18
17
  this.configService = configService;
19
18
  }
20
19
  /**
21
- * Get unified order tracking information from Omuni and Shopify.
20
+ * Get complete order tracking information from Shopify.
22
21
  */
23
22
  async getOrderTracking(brand, input) {
24
- // Fetch from both sources in parallel
25
- const [omuniData, shopifyData] = await Promise.all([
26
- this.fetchFromOmuni(brand, input),
27
- this.fetchFromShopify(brand, input.orderId),
28
- ]);
29
- // Combine responses
30
- return {
31
- // Omuni data
32
- showLoginOTP: omuniData?.showLoginOTP ?? false,
33
- statusTrackingUrl: omuniData?.statusTrackingUrl,
34
- logisticsTrackingUrl: omuniData?.logisticsTrackingUrl,
35
- itemStatuses: omuniData?.itemStatuses,
36
- // Shopify data
37
- orderDetails: shopifyData?.orderDetails,
38
- trackingTimeline: shopifyData?.trackingTimeline,
39
- };
40
- }
41
- /**
42
- * Fetch order tracking data from Omuni OMS.
43
- */
44
- async fetchFromOmuni(brand, input) {
45
- const omsService = this.integrationFactory.get(brand, 'oms');
46
- if (!omsService) {
47
- core_1.logger.warn('OMS integration not configured, skipping Omuni tracking', { brand });
48
- return null;
49
- }
50
- const request = {
51
- entityType: input.entityType ?? 'SHOPIFY',
52
- marketPlaceOrderId: input.orderId,
53
- showItemStatus: input.showItemStatus !== false ? 'YES' : 'NO',
54
- };
55
- try {
56
- const response = await omsService.trackOrder(request);
57
- if (!response.success || !response.data) {
58
- core_1.logger.warn('Omuni tracking request failed', {
59
- brand,
60
- orderId: input.orderId,
61
- error: response.error,
62
- });
63
- return null;
64
- }
65
- const data = response.data.data;
66
- const itemStatuses = data.itemStatus?.map((item) => ({
67
- itemId: item.itemId,
68
- marketPlaceItemId: item.marketPlaceItemId,
69
- status: item.itemStatus,
70
- }));
23
+ const result = await this.fetchFromShopify(brand, input.orderId);
24
+ if (!result) {
71
25
  return {
72
- showLoginOTP: data.showLoginOTP ?? false,
73
- statusTrackingUrl: data.statusTrackingUrl,
74
- logisticsTrackingUrl: data.logisticsTrackingUrl,
75
- itemStatuses,
26
+ trackingUrl: undefined,
27
+ orderDetails: undefined,
28
+ trackingTimeline: undefined,
29
+ lineItems: undefined,
30
+ cancellation: undefined,
31
+ returns: undefined,
32
+ refunds: undefined,
76
33
  };
77
34
  }
78
- catch (error) {
79
- core_1.logger.error('Omuni tracking fetch failed', {
80
- brand,
81
- orderId: input.orderId,
82
- error: error instanceof Error ? error.message : 'Unknown',
83
- });
84
- return null;
85
- }
35
+ return result;
86
36
  }
87
37
  /**
88
- * Fetch order details and fulfillment events from Shopify Admin API.
38
+ * Fetch complete order details from Shopify Admin API.
89
39
  */
90
40
  async fetchFromShopify(brand, orderId) {
91
41
  const adminConfig = this.getShopifyAdminConfig(brand);
92
42
  if (!adminConfig) {
93
- core_1.logger.warn('Shopify Admin API not configured, skipping Shopify data', { brand });
43
+ core_1.logger.warn('Shopify Admin API not configured', { brand });
94
44
  return null;
95
45
  }
96
46
  // Build query filter - support both order name (#1001) and order ID
@@ -105,40 +55,67 @@ let OrderTrackingService = class OrderTrackingService {
105
55
  id
106
56
  name
107
57
  createdAt
58
+ updatedAt
59
+ processedAt
108
60
  displayFinancialStatus
109
61
  displayFulfillmentStatus
110
62
  cancelledAt
63
+ cancelReason
111
64
  closedAt
65
+ confirmed
112
66
  paymentGatewayNames
67
+ channelInformation {
68
+ app { title }
69
+ channelDefinition { channelName }
70
+ }
71
+ subtotalPriceSet { shopMoney { amount currencyCode } }
72
+ totalShippingPriceSet { shopMoney { amount currencyCode } }
73
+ totalTaxSet { shopMoney { amount currencyCode } }
74
+ totalPriceSet { shopMoney { amount currencyCode } }
75
+ billingAddress {
76
+ name firstName lastName
77
+ address1 address2
78
+ city province provinceCode
79
+ country countryCode zip phone
80
+ }
81
+ shippingAddress {
82
+ name firstName lastName
83
+ address1 address2
84
+ city province provinceCode
85
+ country countryCode zip phone
86
+ }
113
87
  shippingLines(first: 5) {
88
+ edges {
89
+ node { title code }
90
+ }
91
+ }
92
+ lineItems(first: 50) {
114
93
  edges {
115
94
  node {
116
- title
117
- code
95
+ id name sku quantity variantTitle fulfillmentStatus
96
+ originalUnitPriceSet { shopMoney { amount currencyCode } }
97
+ originalTotalSet { shopMoney { amount currencyCode } }
98
+ image { url }
99
+ variant {
100
+ selectedOptions { name value }
101
+ }
118
102
  }
119
103
  }
120
104
  }
121
105
  fulfillments {
122
- status
123
- createdAt
124
- deliveredAt
125
- estimatedDeliveryAt
126
- trackingInfo {
127
- number
128
- company
129
- url
130
- }
131
- events(first: 20) {
106
+ id status displayStatus
107
+ createdAt updatedAt deliveredAt inTransitAt estimatedDeliveryAt
108
+ trackingInfo { number company url }
109
+ events(first: 30) {
132
110
  edges {
133
- node {
134
- status
135
- happenedAt
136
- city
137
- province
138
- }
111
+ node { status happenedAt city province message }
139
112
  }
140
113
  }
141
114
  }
115
+ refunds {
116
+ id createdAt note
117
+ totalRefundedSet { shopMoney { amount currencyCode } }
118
+ }
142
119
  }
143
120
  }
144
121
  }
@@ -176,8 +153,13 @@ let OrderTrackingService = class OrderTrackingService {
176
153
  }
177
154
  const order = orderEdge.node;
178
155
  return {
156
+ trackingUrl: this.getTrackingUrl(order),
179
157
  orderDetails: this.mapOrderDetails(order),
180
158
  trackingTimeline: this.buildTrackingTimeline(order),
159
+ lineItems: this.mapLineItems(order),
160
+ cancellation: this.mapCancellation(order),
161
+ returns: this.mapReturns(order),
162
+ refunds: this.mapRefunds(order),
181
163
  };
182
164
  }
183
165
  catch (error) {
@@ -189,6 +171,13 @@ let OrderTrackingService = class OrderTrackingService {
189
171
  return null;
190
172
  }
191
173
  }
174
+ /**
175
+ * Get tracking URL from fulfillment.
176
+ */
177
+ getTrackingUrl(order) {
178
+ const fulfillment = order.fulfillments?.[0];
179
+ return fulfillment?.trackingInfo?.[0]?.url;
180
+ }
192
181
  /**
193
182
  * Map Shopify order to OrderDetails type.
194
183
  */
@@ -202,7 +191,7 @@ let OrderTrackingService = class OrderTrackingService {
202
191
  orderStatus = 'cancelled';
203
192
  }
204
193
  else if (order.displayFulfillmentStatus === 'FULFILLED') {
205
- orderStatus = 'fulfilled';
194
+ orderStatus = fulfillment?.deliveredAt ? 'delivered' : 'fulfilled';
206
195
  }
207
196
  else if (order.displayFulfillmentStatus === 'PARTIALLY_FULFILLED') {
208
197
  orderStatus = 'partially_fulfilled';
@@ -210,22 +199,141 @@ let OrderTrackingService = class OrderTrackingService {
210
199
  else if (order.displayFulfillmentStatus === 'IN_PROGRESS') {
211
200
  orderStatus = 'processing';
212
201
  }
213
- // Format payment method
214
- const paymentMethod = this.formatPaymentMethod(order.paymentGatewayNames);
202
+ else if (order.confirmed) {
203
+ orderStatus = 'confirmed';
204
+ }
205
+ // Check if order can be cancelled
206
+ const orderAgeMinutes = (Date.now() - new Date(order.createdAt).getTime()) / (1000 * 60);
207
+ const canCancel = !order.cancelledAt &&
208
+ order.displayFulfillmentStatus === 'UNFULFILLED' &&
209
+ orderAgeMinutes <= CANCELLATION_WINDOW_MINUTES;
210
+ let cancellationMessage;
211
+ if (!canCancel && !order.cancelledAt) {
212
+ if (order.displayFulfillmentStatus !== 'UNFULFILLED') {
213
+ cancellationMessage = 'We have already started the shipping process.';
214
+ }
215
+ else {
216
+ cancellationMessage = `Unfortunately, the approximate ${CANCELLATION_WINDOW_MINUTES} minute window for cancelling this order has passed.`;
217
+ }
218
+ }
219
+ // Get channel name
220
+ const channelName = order.channelInformation?.channelDefinition?.channelName ||
221
+ order.channelInformation?.app?.title ||
222
+ 'Online Store';
215
223
  return {
216
224
  orderId: order.id,
217
225
  orderName: order.name,
218
226
  orderStatus,
219
227
  fulfillmentStatus: order.displayFulfillmentStatus?.toLowerCase(),
228
+ financialStatus: order.displayFinancialStatus?.toLowerCase(),
229
+ channelName,
220
230
  shippingMethod: shippingLine?.title,
221
- paymentMethod,
231
+ paymentMethod: this.formatPaymentMethod(order.paymentGatewayNames),
222
232
  trackingNumber: trackingInfo?.number,
223
233
  carrierName: trackingInfo?.company,
234
+ trackingUrl: trackingInfo?.url,
224
235
  createdAt: order.createdAt,
225
- expectedDeliveryAt: fulfillment?.estimatedDeliveryAt,
236
+ estimatedDeliveryAt: fulfillment?.estimatedDeliveryAt,
226
237
  deliveredAt: fulfillment?.deliveredAt,
238
+ subtotal: this.mapMoney(order.subtotalPriceSet.shopMoney),
239
+ shippingCost: this.mapMoney(order.totalShippingPriceSet.shopMoney),
240
+ totalTax: this.mapMoney(order.totalTaxSet.shopMoney),
241
+ totalAmount: this.mapMoney(order.totalPriceSet.shopMoney),
242
+ billingAddress: order.billingAddress ? this.mapAddress(order.billingAddress) : undefined,
243
+ shippingAddress: order.shippingAddress ? this.mapAddress(order.shippingAddress) : undefined,
244
+ canCancel,
245
+ cancellationMessage,
227
246
  };
228
247
  }
248
+ /**
249
+ * Map line items from Shopify order.
250
+ */
251
+ mapLineItems(order) {
252
+ return order.lineItems.edges.map(({ node }) => {
253
+ const variantOptions = node.variant?.selectedOptions?.map(opt => ({
254
+ name: opt.name,
255
+ value: opt.value,
256
+ })) || [];
257
+ return {
258
+ id: node.id,
259
+ name: node.name,
260
+ sku: node.sku,
261
+ quantity: node.quantity,
262
+ unitPrice: this.mapMoney(node.originalUnitPriceSet.shopMoney),
263
+ totalPrice: this.mapMoney(node.originalTotalSet.shopMoney),
264
+ imageUrl: node.image?.url,
265
+ variantTitle: node.variantTitle,
266
+ variantOptions,
267
+ fulfillmentStatus: node.fulfillmentStatus?.toLowerCase(),
268
+ };
269
+ });
270
+ }
271
+ /**
272
+ * Map cancellation info if order was cancelled.
273
+ */
274
+ mapCancellation(order) {
275
+ if (!order.cancelledAt) {
276
+ return undefined;
277
+ }
278
+ // Map cancel reason to human readable text
279
+ const reasonMap = {
280
+ CUSTOMER: 'Customer requested cancellation',
281
+ FRAUD: 'Suspected fraudulent order',
282
+ INVENTORY: 'Items out of stock',
283
+ DECLINED: 'Payment declined',
284
+ OTHER: 'Other reason',
285
+ };
286
+ const refund = order.refunds?.[0];
287
+ return {
288
+ cancelledAt: order.cancelledAt,
289
+ reason: order.cancelReason ? reasonMap[order.cancelReason] || order.cancelReason : undefined,
290
+ refund: refund ? {
291
+ id: refund.id,
292
+ createdAt: refund.createdAt,
293
+ totalRefunded: this.mapMoney(refund.totalRefundedSet.shopMoney),
294
+ note: refund.note,
295
+ } : undefined,
296
+ };
297
+ }
298
+ /**
299
+ * Map returns from Shopify order.
300
+ */
301
+ mapReturns(order) {
302
+ const returns = order.returns?.edges;
303
+ if (!returns || returns.length === 0) {
304
+ return undefined;
305
+ }
306
+ return returns.map(({ node }) => {
307
+ const items = node.returnLineItems.edges.map(({ node: rli }) => ({
308
+ id: rli.id,
309
+ name: rli.fulfillmentLineItem?.lineItem?.name || 'Unknown Item',
310
+ quantity: rli.quantity,
311
+ imageUrl: rli.fulfillmentLineItem?.lineItem?.image?.url,
312
+ returnReason: rli.returnReason,
313
+ }));
314
+ return {
315
+ id: node.id,
316
+ status: node.status,
317
+ createdAt: node.createdAt,
318
+ itemCount: items.length,
319
+ items,
320
+ };
321
+ });
322
+ }
323
+ /**
324
+ * Map refunds from Shopify order.
325
+ */
326
+ mapRefunds(order) {
327
+ if (!order.refunds || order.refunds.length === 0) {
328
+ return undefined;
329
+ }
330
+ return order.refunds.map(refund => ({
331
+ id: refund.id,
332
+ createdAt: refund.createdAt,
333
+ totalRefunded: this.mapMoney(refund.totalRefundedSet.shopMoney),
334
+ note: refund.note,
335
+ }));
336
+ }
229
337
  /**
230
338
  * Build tracking timeline from Shopify fulfillment events.
231
339
  */
@@ -233,7 +341,7 @@ let OrderTrackingService = class OrderTrackingService {
233
341
  const timeline = [];
234
342
  // Define the standard tracking stages
235
343
  const stages = [
236
- { status: 'ordered', label: 'Ordered' },
344
+ { status: 'ordered', label: 'Order placed' },
237
345
  { status: 'confirmed', label: 'Confirmed' },
238
346
  { status: 'in_transit', label: 'Shipped' },
239
347
  { status: 'out_for_delivery', label: 'Out for Delivery' },
@@ -249,66 +357,99 @@ let OrderTrackingService = class OrderTrackingService {
249
357
  // Map events by status (use latest event for each status)
250
358
  const eventsByStatus = new Map();
251
359
  for (const event of allEvents) {
252
- const normalizedStatus = event.status.toLowerCase().replace(/_/g, '_');
360
+ const normalizedStatus = event.status.toLowerCase();
253
361
  const existing = eventsByStatus.get(normalizedStatus);
254
362
  if (!existing || new Date(event.happenedAt) > new Date(existing.happenedAt)) {
255
363
  eventsByStatus.set(normalizedStatus, event);
256
364
  }
257
365
  }
258
- // Always add "Ordered" as first event (from order creation)
259
- const orderedEvent = {
260
- status: 'ordered',
261
- label: 'Ordered',
262
- happenedAt: order.createdAt,
263
- isCompleted: true,
264
- isCurrent: false,
265
- };
266
- timeline.push(orderedEvent);
267
- // Determine current status
268
- let currentStatusIndex = 0; // Default to "ordered"
366
+ // Determine current status index
367
+ let currentStatusIndex = 0;
269
368
  const fulfillment = order.fulfillments?.[0];
270
- if (fulfillment) {
271
- const fulfillmentStatus = fulfillment.status?.toLowerCase();
272
- if (fulfillmentStatus === 'delivered' || fulfillment.deliveredAt) {
273
- currentStatusIndex = 4; // delivered
369
+ if (order.cancelledAt) {
370
+ currentStatusIndex = -1; // Cancelled
371
+ }
372
+ else if (fulfillment) {
373
+ if (fulfillment.deliveredAt || eventsByStatus.has('delivered')) {
374
+ currentStatusIndex = 4;
274
375
  }
275
376
  else if (eventsByStatus.has('out_for_delivery')) {
276
377
  currentStatusIndex = 3;
277
378
  }
278
- else if (eventsByStatus.has('in_transit') || fulfillmentStatus === 'in_transit') {
379
+ else if (fulfillment.inTransitAt || eventsByStatus.has('in_transit')) {
279
380
  currentStatusIndex = 2;
280
381
  }
281
382
  else if (eventsByStatus.has('confirmed') || fulfillment.createdAt) {
282
383
  currentStatusIndex = 1;
283
384
  }
284
385
  }
285
- // Build remaining timeline stages
286
- for (let i = 1; i < stages.length; i++) {
386
+ else if (order.confirmed) {
387
+ currentStatusIndex = 0;
388
+ }
389
+ // Build timeline
390
+ for (let i = 0; i < stages.length; i++) {
287
391
  const stage = stages[i];
288
392
  const event = eventsByStatus.get(stage.status);
289
- // For "confirmed" stage, use fulfillment creation if no explicit event
290
- let happenedAt = event?.happenedAt;
291
- if (stage.status === 'confirmed' && !happenedAt && fulfillment?.createdAt) {
292
- happenedAt = fulfillment.createdAt;
393
+ let happenedAt;
394
+ // Determine timestamp for each stage
395
+ if (stage.status === 'ordered') {
396
+ happenedAt = order.createdAt;
293
397
  }
294
- // For "delivered" stage, use deliveredAt if available
295
- if (stage.status === 'delivered' && !happenedAt && fulfillment?.deliveredAt) {
296
- happenedAt = fulfillment.deliveredAt;
398
+ else if (stage.status === 'confirmed') {
399
+ happenedAt = event?.happenedAt || fulfillment?.createdAt;
297
400
  }
298
- const isCompleted = i <= currentStatusIndex;
401
+ else if (stage.status === 'in_transit') {
402
+ happenedAt = event?.happenedAt || fulfillment?.inTransitAt;
403
+ }
404
+ else if (stage.status === 'out_for_delivery') {
405
+ happenedAt = event?.happenedAt;
406
+ }
407
+ else if (stage.status === 'delivered') {
408
+ happenedAt = event?.happenedAt || fulfillment?.deliveredAt;
409
+ }
410
+ const isCompleted = currentStatusIndex >= 0 && i <= currentStatusIndex;
299
411
  const isCurrent = i === currentStatusIndex;
300
412
  timeline.push({
301
413
  status: stage.status,
302
414
  label: stage.label,
303
- happenedAt: happenedAt,
415
+ happenedAt,
304
416
  city: event?.city,
305
417
  province: event?.province,
418
+ message: event?.message,
306
419
  isCompleted,
307
420
  isCurrent,
308
421
  });
309
422
  }
310
423
  return timeline;
311
424
  }
425
+ /**
426
+ * Map Shopify money to OrderMoney type.
427
+ */
428
+ mapMoney(money) {
429
+ return {
430
+ amount: money.amount,
431
+ currencyCode: money.currencyCode,
432
+ };
433
+ }
434
+ /**
435
+ * Map Shopify address to OrderAddress type.
436
+ */
437
+ mapAddress(addr) {
438
+ return {
439
+ name: addr.name,
440
+ firstName: addr.firstName,
441
+ lastName: addr.lastName,
442
+ address1: addr.address1,
443
+ address2: addr.address2,
444
+ city: addr.city,
445
+ province: addr.province,
446
+ provinceCode: addr.provinceCode,
447
+ country: addr.country,
448
+ countryCode: addr.countryCode,
449
+ zip: addr.zip,
450
+ phone: addr.phone,
451
+ };
452
+ }
312
453
  /**
313
454
  * Format payment gateway names to readable format.
314
455
  */
@@ -316,7 +457,6 @@ let OrderTrackingService = class OrderTrackingService {
316
457
  if (!gatewayNames || gatewayNames.length === 0) {
317
458
  return 'Unknown';
318
459
  }
319
- // Common payment gateway mappings
320
460
  const gatewayMap = {
321
461
  'cash_on_delivery': 'COD',
322
462
  'cod': 'COD',
@@ -328,12 +468,15 @@ let OrderTrackingService = class OrderTrackingService {
328
468
  'phonepe': 'PhonePe',
329
469
  'upi': 'UPI',
330
470
  'gokwik': 'GoKwik',
471
+ 'ideal': 'iDEAL',
331
472
  };
332
473
  const gateway = gatewayNames[0].toLowerCase();
333
- // Check for UPI in gateway name
334
- if (gateway.includes('upi')) {
474
+ if (gateway.includes('upi'))
335
475
  return 'UPI';
336
- }
476
+ if (gateway.includes('ideal'))
477
+ return 'iDEAL';
478
+ if (gateway.includes('credit') || gateway.includes('card'))
479
+ return 'Credit Card';
337
480
  return gatewayMap[gateway] || this.capitalizeFirst(gatewayNames[0].replace(/_/g, ' '));
338
481
  }
339
482
  /**
@@ -365,7 +508,6 @@ let OrderTrackingService = class OrderTrackingService {
365
508
  exports.OrderTrackingService = OrderTrackingService;
366
509
  exports.OrderTrackingService = OrderTrackingService = tslib_1.__decorate([
367
510
  (0, common_1.Injectable)(),
368
- tslib_1.__metadata("design:paramtypes", [core_1.IntegrationFactory,
369
- core_1.ConfigService])
511
+ tslib_1.__metadata("design:paramtypes", [core_1.ConfigService])
370
512
  ], OrderTrackingService);
371
513
  //# sourceMappingURL=order-tracking.service.js.map