@faststore/api 2.1.9 → 2.1.24

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.
@@ -38,18 +38,12 @@ export declare const VtexCommerce: ({ account, environment, incrementAddress }:
38
38
  checkout: {
39
39
  simulation: (args: SimulationArgs, { salesChannel }?: SimulationOptions) => Promise<Simulation>;
40
40
  incrementAddress: (country: string, postalCode: string) => Promise<IncrementedAddress>;
41
- getDeliveryWindows: ({ id, index, deliveryMode, body, }: {
42
- id: string;
43
- index: number;
44
- deliveryMode?: DeliveryMode | null | undefined;
45
- body: ShippingDataBody;
46
- }, incrementedAddress?: IncrementedAddress | undefined) => Promise<OrderForm>;
47
41
  shippingData: ({ id, index, deliveryMode, body, }: {
48
42
  id: string;
49
43
  index: number;
50
44
  deliveryMode?: DeliveryMode | null | undefined;
51
45
  body: ShippingDataBody;
52
- }, incrementedAddress?: IncrementedAddress | undefined) => Promise<OrderForm>;
46
+ }, incrementedAddress?: IncrementedAddress | undefined, setDeliveryWindow?: boolean | undefined) => Promise<OrderForm>;
53
47
  orderForm: ({ id, refreshOutdatedData, channel, }: {
54
48
  id: string;
55
49
  refreshOutdatedData?: boolean | undefined;
@@ -271,7 +271,7 @@ export interface SLA {
271
271
  shippingEstimateDate: string | null;
272
272
  lockTTL: string | null;
273
273
  availableDeliveryWindows: AvailableDeliveryWindows[];
274
- deliveryWindow: string | null;
274
+ deliveryWindow: DeliveryWindow | null;
275
275
  price: number;
276
276
  listPrice: number;
277
277
  tax: number;
@@ -287,6 +287,10 @@ export interface SLA {
287
287
  polygonName: string | null;
288
288
  transitTime: string | null;
289
289
  }
290
+ export interface DeliveryWindow {
291
+ startDateUtc: string;
292
+ endDateUtc: string;
293
+ }
290
294
  export interface AvailableDeliveryWindows {
291
295
  startDateUtc: string;
292
296
  endDateUtc: string;
@@ -30,18 +30,12 @@ export declare const getClients: (options: Options, ctx: Context) => {
30
30
  checkout: {
31
31
  simulation: (args: import("./commerce/types/Simulation").SimulationArgs, { salesChannel }?: import("./commerce/types/Simulation").SimulationOptions) => Promise<import("./commerce/types/Simulation").Simulation>;
32
32
  incrementAddress: (country: string, postalCode: string) => Promise<import("./commerce/types/IncrementedAddress").IncrementedAddress>;
33
- getDeliveryWindows: ({ id, index, deliveryMode, body, }: {
34
- id: string;
35
- index: number;
36
- deliveryMode?: import("./commerce/types/ShippingData").DeliveryMode | null | undefined;
37
- body: import("./commerce/types/ShippingData").ShippingDataBody;
38
- }, incrementedAddress?: import("./commerce/types/IncrementedAddress").IncrementedAddress | undefined) => Promise<import("./commerce/types/OrderForm").OrderForm>;
39
33
  shippingData: ({ id, index, deliveryMode, body, }: {
40
34
  id: string;
41
35
  index: number;
42
36
  deliveryMode?: import("./commerce/types/ShippingData").DeliveryMode | null | undefined;
43
37
  body: import("./commerce/types/ShippingData").ShippingDataBody;
44
- }, incrementedAddress?: import("./commerce/types/IncrementedAddress").IncrementedAddress | undefined) => Promise<import("./commerce/types/OrderForm").OrderForm>;
38
+ }, incrementedAddress?: import("./commerce/types/IncrementedAddress").IncrementedAddress | undefined, setDeliveryWindow?: boolean | undefined) => Promise<import("./commerce/types/OrderForm").OrderForm>;
45
39
  orderForm: ({ id, refreshOutdatedData, channel, }: {
46
40
  id: string;
47
41
  refreshOutdatedData?: boolean | undefined;
@@ -0,0 +1,3 @@
1
+ import { IStoreSession } from '../../../__generated__/schema';
2
+ import { OrderForm } from '../clients/commerce/types/OrderForm';
3
+ export declare const shouldUpdateShippingData: (orderForm: OrderForm, session: IStoreSession) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/api",
3
- "version": "2.1.9",
3
+ "version": "2.1.24",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -56,5 +56,5 @@
56
56
  "@envelop/core": "^1 || ^2",
57
57
  "graphql": "^15.6.0"
58
58
  },
59
- "gitHead": "e8c0051ff4e990fcf9375bc8a22f76570967e1af"
59
+ "gitHead": "38bb4d96f41615c87fe93b6b88e6b0e8d034b97e"
60
60
  }
@@ -113,7 +113,7 @@ export const VtexCommerce = (
113
113
  : Promise.resolve(undefined)
114
114
  },
115
115
 
116
- getDeliveryWindows: (
116
+ shippingData: (
117
117
  {
118
118
  id,
119
119
  index,
@@ -125,76 +125,47 @@ export const VtexCommerce = (
125
125
  deliveryMode?: DeliveryMode | null
126
126
  body: ShippingDataBody
127
127
  },
128
- incrementedAddress?: IncrementedAddress
128
+ incrementedAddress?: IncrementedAddress,
129
+ setDeliveryWindow?: boolean
129
130
  ): Promise<OrderForm> => {
130
- const mappedBody = {
131
- logisticsInfo: Array.from({ length: index }, (_, itemIndex) => ({
132
- itemIndex,
133
- selectedDeliveryChannel: deliveryMode?.deliveryChannel || null,
134
- selectedSla: deliveryMode?.deliveryMethod || null,
135
- })),
136
- selectedAddresses: body?.selectedAddresses?.map((address) => {
137
- const selectedAddress: SelectedAddress = {
138
- addressType: address.addressType || null,
139
- receiverName: address.receiverName || null,
140
- postalCode:
141
- address.postalCode || incrementedAddress?.postalCode || null,
142
- city: incrementedAddress?.city || null,
143
- state: incrementedAddress?.state || null,
144
- country: address.country || incrementedAddress?.country || null,
145
- street: incrementedAddress?.street || null,
146
- number: incrementedAddress?.number || null,
147
- neighborhood: incrementedAddress?.neighborhood || null,
148
- complement: incrementedAddress?.complement || null,
149
- reference: incrementedAddress?.reference || null,
150
- geoCoordinates: [], // Initialize with default value
151
- }
152
-
153
- const longitude =
154
- address?.geoCoordinates instanceof Array
155
- ? null
156
- : address?.geoCoordinates?.longitude || null
131
+ const addressSession = body?.selectedAddresses?.map((address) => {
132
+ const addressSession: SelectedAddress = {
133
+ addressType: address.addressType || null,
134
+ receiverName: address.receiverName || null,
135
+ postalCode:
136
+ address.postalCode || incrementedAddress?.postalCode || null,
137
+ city: incrementedAddress?.city || null,
138
+ state: incrementedAddress?.state || null,
139
+ country: address.country || incrementedAddress?.country || null,
140
+ street: incrementedAddress?.street || null,
141
+ number: incrementedAddress?.number || null,
142
+ neighborhood: incrementedAddress?.neighborhood || null,
143
+ complement: incrementedAddress?.complement || null,
144
+ reference: incrementedAddress?.reference || null,
145
+ geoCoordinates: [], // Initialize with default value
146
+ }
157
147
 
148
+ const geoCoordinates = address?.geoCoordinates
149
+ if (geoCoordinates) {
158
150
  const latitude =
159
- address?.geoCoordinates instanceof Array
160
- ? null
161
- : address?.geoCoordinates?.latitude || null
151
+ typeof geoCoordinates === 'object' && 'latitude' in geoCoordinates
152
+ ? geoCoordinates.latitude
153
+ : null
154
+ const longitude =
155
+ typeof geoCoordinates === 'object' &&
156
+ 'longitude' in geoCoordinates
157
+ ? geoCoordinates.longitude
158
+ : null
162
159
 
163
- selectedAddress.geoCoordinates =
164
- longitude && latitude
165
- ? { longitude, latitude }
160
+ addressSession.geoCoordinates =
161
+ latitude !== null && longitude !== null
162
+ ? [longitude, latitude]
166
163
  : incrementedAddress?.geoCoordinates || []
167
-
168
- return selectedAddress
169
- }),
170
- }
171
-
172
- return fetchAPI(
173
- `${base}/api/checkout/pub/orderForm/${id}/attachments/shippingData`,
174
- {
175
- ...BASE_INIT,
176
- body: JSON.stringify(mappedBody),
177
164
  }
178
- )
179
- },
180
-
181
- shippingData: (
182
- {
183
- id,
184
- index,
185
- deliveryMode,
186
- body,
187
- }: {
188
- id: string
189
- index: number
190
- deliveryMode?: DeliveryMode | null
191
- body: ShippingDataBody
192
- },
193
- incrementedAddress?: IncrementedAddress
194
- ): Promise<OrderForm> => {
195
- const hasDeliveryWindow = deliveryMode?.deliveryWindow ? true : false
165
+ return addressSession
166
+ })
196
167
 
197
- const deliveryWindow = hasDeliveryWindow
168
+ const deliveryWindow = setDeliveryWindow
198
169
  ? {
199
170
  startDateUtc: deliveryMode?.deliveryWindow?.startDate,
200
171
  endDateUtc: deliveryMode?.deliveryWindow?.endDate,
@@ -208,40 +179,8 @@ export const VtexCommerce = (
208
179
  selectedSla: deliveryMode?.deliveryMethod || null,
209
180
  deliveryWindow: deliveryWindow,
210
181
  })),
211
- selectedAddresses: body?.selectedAddresses?.map((address) => {
212
- const selectedAddress: SelectedAddress = {
213
- addressType: address.addressType || null,
214
- receiverName: address.receiverName || null,
215
- postalCode:
216
- address.postalCode || incrementedAddress?.postalCode || null,
217
- city: incrementedAddress?.city || null,
218
- state: incrementedAddress?.state || null,
219
- country: address.country || incrementedAddress?.country || null,
220
- street: incrementedAddress?.street || null,
221
- number: incrementedAddress?.number || null,
222
- neighborhood: incrementedAddress?.neighborhood || null,
223
- complement: incrementedAddress?.complement || null,
224
- reference: incrementedAddress?.reference || null,
225
- geoCoordinates: [], // Initialize with default value
226
- }
227
-
228
- const longitude =
229
- address?.geoCoordinates instanceof Array
230
- ? null
231
- : address?.geoCoordinates?.longitude || null
232
-
233
- const latitude =
234
- address?.geoCoordinates instanceof Array
235
- ? null
236
- : address?.geoCoordinates?.latitude || null
237
-
238
- selectedAddress.geoCoordinates =
239
- longitude && latitude
240
- ? [longitude, latitude]
241
- : incrementedAddress?.geoCoordinates || []
242
-
243
- return selectedAddress
244
- }),
182
+ selectedAddresses: addressSession,
183
+ address: addressSession,
245
184
  }
246
185
 
247
186
  return fetchAPI(
@@ -288,7 +288,7 @@ export interface SLA {
288
288
  shippingEstimateDate: string | null
289
289
  lockTTL: string | null
290
290
  availableDeliveryWindows: AvailableDeliveryWindows[]
291
- deliveryWindow: string | null
291
+ deliveryWindow: DeliveryWindow | null
292
292
  price: number
293
293
  listPrice: number
294
294
  tax: number
@@ -305,6 +305,11 @@ export interface SLA {
305
305
  transitTime: string | null
306
306
  }
307
307
 
308
+ export interface DeliveryWindow {
309
+ startDateUtc: string
310
+ endDateUtc: string
311
+ }
312
+
308
313
  export interface AvailableDeliveryWindows {
309
314
  startDateUtc: string,
310
315
  endDateUtc: string,
@@ -24,6 +24,7 @@ import type {
24
24
  OrderFormItem,
25
25
  } from '../clients/commerce/types/OrderForm'
26
26
  import { IncrementedAddress } from '../clients/commerce/types/IncrementedAddress'
27
+ import { shouldUpdateShippingData } from '../utils/shouldUpdateShippingData'
27
28
 
28
29
  type Indexed<T> = T & { index?: number }
29
30
 
@@ -234,21 +235,11 @@ const getOrderForm = async (
234
235
  return orderForm
235
236
  }
236
237
 
237
- const shouldUpdateShippingData =
238
- orderForm.items.length > 0 &&
239
- (typeof session.postalCode === 'string' &&
240
- orderForm.shippingData?.address?.postalCode !== session.postalCode) ||
241
- (typeof session.geoCoordinates === 'object' &&
242
- typeof session.geoCoordinates?.latitude === 'number' &&
243
- typeof session.geoCoordinates.longitude === 'number' &&
244
- (orderForm.shippingData?.address?.geoCoordinates[0] !==
245
- session.geoCoordinates.longitude ||
246
- orderForm.shippingData?.address?.geoCoordinates[1] !==
247
- session.geoCoordinates.latitude))
248
-
249
- if (shouldUpdateShippingData) {
238
+ const updateShipping = shouldUpdateShippingData(orderForm, session)
239
+
240
+ if (updateShipping) {
250
241
  let incrementedAddress: IncrementedAddress | undefined
251
-
242
+
252
243
  if (session.postalCode) {
253
244
  incrementedAddress = await commerce.checkout.incrementAddress(
254
245
  session.country,
@@ -261,7 +252,7 @@ const getOrderForm = async (
261
252
 
262
253
  if (hasDeliveryWindow) {
263
254
  // if you have a Delivery Window you have to first get the delivery window to set the desired after
264
- await commerce.checkout.getDeliveryWindows(
255
+ await commerce.checkout.shippingData(
265
256
  {
266
257
  id: orderForm.orderFormId,
267
258
  index: orderForm.items.length,
@@ -270,10 +261,11 @@ const getOrderForm = async (
270
261
  selectedAddresses: [session],
271
262
  },
272
263
  },
273
- incrementedAddress
264
+ incrementedAddress,
265
+ false
274
266
  )
275
267
  }
276
-
268
+
277
269
  return commerce.checkout.shippingData(
278
270
  {
279
271
  id: orderForm.orderFormId,
@@ -283,7 +275,8 @@ const getOrderForm = async (
283
275
  selectedAddresses: [session],
284
276
  },
285
277
  },
286
- incrementedAddress
278
+ incrementedAddress,
279
+ true
287
280
  )
288
281
  }
289
282
 
@@ -340,7 +333,16 @@ export const validateCart = async (
340
333
  // Step1: Get OrderForm from VTEX Commerce
341
334
  const orderForm = await getOrderForm(orderNumber, session, ctx)
342
335
 
343
- // Step1.5: Check if another system changed the orderForm with this orderNumber
336
+ // Step1.1: Checks if the orderForm id has changed. There are three cases for this:
337
+ // Social Selling: the vtex_session cookie contains a new orderForm id with Social Selling data
338
+ // My Orders: the customer clicks on reordering through generating a new cart and when returning to the faststore, this information needs to be returned by vtex_session cookie.
339
+ // New session: a new user enters the website and has no orderForm attributed to it (has no relation to the vtex_session cookie).
340
+ // In all cases, the origin orderForm should replace the copy that's in the browser
341
+ if (orderForm.orderFormId != orderNumberFromCart) {
342
+ return orderFormToCart(orderForm, skuLoader)
343
+ }
344
+
345
+ // Step1.2: Check if another system changed the orderForm with this orderNumber
344
346
  // If so, this means the user interacted with this cart elsewhere and expects
345
347
  // to see this new cart state instead of what's stored on the user's browser.
346
348
  const isStale = isOrderFormStale(orderForm)
@@ -0,0 +1,155 @@
1
+ import {
2
+ IStoreGeoCoordinates,
3
+ IStoreSession,
4
+ } from '../../../__generated__/schema'
5
+ import {
6
+ CheckoutAddress,
7
+ OrderForm,
8
+ LogisticsInfo,
9
+ } from '../clients/commerce/types/OrderForm'
10
+
11
+ export const shouldUpdateShippingData = (
12
+ orderForm: OrderForm,
13
+ session: IStoreSession
14
+ ) => {
15
+ if (!hasSessionPostalCodeOrGeoCoordinates(session)) {
16
+ return false
17
+ }
18
+
19
+ const { address } = orderForm.shippingData ?? { address: null }
20
+
21
+ if (checkPostalCode(address, session.postalCode)) {
22
+ return true
23
+ }
24
+
25
+ if (checkGeoCoordinates(address, session.geoCoordinates)) {
26
+ return true
27
+ }
28
+
29
+ if (!hasItems(orderForm)) {
30
+ return false
31
+ }
32
+
33
+ // The logisticsInfo will always exist if there´s at least one item inside the cart
34
+ const { logisticsInfo } = orderForm.shippingData!
35
+
36
+ if (shouldUpdateDeliveryChannel(logisticsInfo, session)) {
37
+ return true
38
+ }
39
+
40
+ if (shouldUpdateDeliveryMethod(logisticsInfo, session)) {
41
+ return true
42
+ }
43
+
44
+ if (shouldUpdateDeliveryWindow(logisticsInfo, session)) {
45
+ return true
46
+ }
47
+ return false
48
+ }
49
+
50
+ // Validate if theres any postal Code or GeoCoordinates set at the session
51
+ const hasSessionPostalCodeOrGeoCoordinates = (session: IStoreSession) => {
52
+ return (
53
+ !!session.postalCode ||
54
+ (session.geoCoordinates &&
55
+ session.geoCoordinates.latitude &&
56
+ session.geoCoordinates.longitude)
57
+ )
58
+ }
59
+
60
+ // Validate if theres a difference between the session postal code and orderForm postal code
61
+ const checkPostalCode = (
62
+ address: CheckoutAddress | null | undefined,
63
+ postalCode: string | null | undefined
64
+ ) => {
65
+ return typeof postalCode === 'string' && address?.postalCode !== postalCode
66
+ }
67
+
68
+ // Validate if theres a difference between the session geoCoords and orderForm geoCoords
69
+ const checkGeoCoordinates = (
70
+ address: CheckoutAddress | null | undefined,
71
+ geoCoordinates: IStoreGeoCoordinates | null | undefined
72
+ ) => {
73
+ return (
74
+ typeof geoCoordinates?.latitude === 'number' &&
75
+ typeof geoCoordinates?.longitude === 'number' &&
76
+ (address?.geoCoordinates[0] !== geoCoordinates?.longitude ||
77
+ address?.geoCoordinates[1] !== geoCoordinates?.latitude)
78
+ )
79
+ }
80
+
81
+ // Validate if theres any item inside the orderForm
82
+ const hasItems = (orderForm: OrderForm) => {
83
+ return orderForm.items.length !== 0
84
+ }
85
+
86
+ // Validate if the deliveryChannel from the session is different from the selected delivery channel
87
+ // and if so needs to validate if the deliveryChannel for the session is available inside the slas for the item
88
+ const shouldUpdateDeliveryChannel = (
89
+ logisticsInfo: LogisticsInfo[],
90
+ session: IStoreSession | null | undefined
91
+ ) => {
92
+ if (!session?.deliveryMode?.deliveryChannel) {
93
+ return false
94
+ }
95
+ const { deliveryChannel } = session.deliveryMode
96
+ for (const item of logisticsInfo) {
97
+ if (item.selectedDeliveryChannel !== deliveryChannel) {
98
+ const matchingSla = item.slas.find(
99
+ (sla) => sla.deliveryChannel === deliveryChannel
100
+ )
101
+ if (matchingSla) {
102
+ return true
103
+ }
104
+ }
105
+ }
106
+ return false
107
+ }
108
+
109
+ // Validate if the deliveryMethod from the session is different from the selectedSLA
110
+ // and if so needs to validate if the deliveryMethod for the session is available inside the slas for the item
111
+ const shouldUpdateDeliveryMethod = (
112
+ logisticsInfo: LogisticsInfo[],
113
+ session: IStoreSession
114
+ ) => {
115
+ if (!session?.deliveryMode?.deliveryMethod) {
116
+ return false
117
+ }
118
+ const { deliveryMethod } = session.deliveryMode
119
+ for (const item of logisticsInfo) {
120
+ if (item.selectedSla !== deliveryMethod) {
121
+ const matchingSla = item.slas.find((sla) => sla.id === deliveryMethod)
122
+ if (matchingSla) {
123
+ return true
124
+ }
125
+ }
126
+ }
127
+ return false
128
+ }
129
+
130
+ // Validate if the deliveryWindow from the session is different from the deliveryWindow of the SLA
131
+ // and if so needs to validate if the deliveryWindow for the session is available inside the availableDeliveryWindows for the item
132
+ const shouldUpdateDeliveryWindow = (
133
+ logisticsInfo: LogisticsInfo[],
134
+ session: IStoreSession
135
+ ) => {
136
+ if (
137
+ !session?.deliveryMode?.deliveryWindow?.startDate ||
138
+ !session?.deliveryMode?.deliveryWindow?.endDate
139
+ ) {
140
+ return false
141
+ }
142
+ const { startDate, endDate } = session.deliveryMode.deliveryWindow
143
+ for (const item of logisticsInfo) {
144
+ for (const sla of item.slas) {
145
+ const matchingWindow = sla.availableDeliveryWindows?.some(
146
+ (window) =>
147
+ window.startDateUtc === startDate && window.endDateUtc === endDate
148
+ )
149
+ if (matchingWindow) {
150
+ return true
151
+ }
152
+ }
153
+ }
154
+ return false
155
+ }