@kizlo/woocommerce 0.1.0
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/LICENSE +21 -0
- package/README.md +47 -0
- package/dist/index.d.ts +2599 -0
- package/dist/index.js +1796 -0
- package/dist/test.d.ts +7 -0
- package/dist/test.js +89 -0
- package/package.json +58 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1796 @@
|
|
|
1
|
+
import { CurrencyFormat, IdentifierInput, KizloError, ListMetadata, Media, Seo, WC_CORE_BASE, WC_STORE_BASE, WP_KIZLO_BASE, createExtension, createMiddleware, createProcedure, defineErrorMap, deserializeCurrencyFormat, deserializeListMetadata } from "kizlo";
|
|
2
|
+
import { BooleanLike, Metadata, NumberLike, arrayable, normalizeArrayableValue, random, seconds, timestampSec, toPublicMetadata, tryCatch } from "@kizlo/shared";
|
|
3
|
+
import { SignJWT, jwtVerify } from "jose";
|
|
4
|
+
import z$1, { z } from "zod/v4";
|
|
5
|
+
import z$2 from "zod";
|
|
6
|
+
|
|
7
|
+
//#region src/session.ts
|
|
8
|
+
async function mintGuestToken(secret, ttlSeconds) {
|
|
9
|
+
const sub = random({
|
|
10
|
+
length: 32,
|
|
11
|
+
prefix: "t"
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
jwt: await new SignJWT().setProtectedHeader({
|
|
15
|
+
alg: "HS256",
|
|
16
|
+
typ: "JWT"
|
|
17
|
+
}).setSubject(sub).setIssuedAt().setExpirationTime(timestampSec() + ttlSeconds).sign(encodeSecret(secret)),
|
|
18
|
+
sub
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async function verifyToken(token, secret) {
|
|
22
|
+
const { payload } = await jwtVerify(token, encodeSecret(secret));
|
|
23
|
+
return payload;
|
|
24
|
+
}
|
|
25
|
+
function encodeSecret(secret) {
|
|
26
|
+
return new TextEncoder().encode(secret);
|
|
27
|
+
}
|
|
28
|
+
function getCartHeaders(options) {
|
|
29
|
+
const { connInfo, userId, token } = options;
|
|
30
|
+
const headers = {};
|
|
31
|
+
if (token) headers["X-Kizlo-Guest-Token"] = token;
|
|
32
|
+
if (userId) headers["X-Kizlo-User-Id"] = String(userId);
|
|
33
|
+
if (connInfo?.city) headers["X-Kizlo-Geo-City"] = connInfo.city;
|
|
34
|
+
if (connInfo?.state) headers["X-Kizlo-Geo-State"] = connInfo.state;
|
|
35
|
+
if (connInfo?.country) headers["X-Kizlo-Geo-Country"] = connInfo.country;
|
|
36
|
+
if (connInfo?.postcode) headers["X-Kizlo-Geo-Postcode"] = connInfo.postcode;
|
|
37
|
+
return headers;
|
|
38
|
+
}
|
|
39
|
+
function sessionMiddleware(options) {
|
|
40
|
+
const cookieName = options?.cookieName ?? "guest-session";
|
|
41
|
+
const ttlSeconds = seconds(options?.ttl ?? "48 hours");
|
|
42
|
+
return createMiddleware(async ({ context, next }) => {
|
|
43
|
+
const connInfo = await context.getConnInfo();
|
|
44
|
+
const auth = await context.getAuthUser();
|
|
45
|
+
const foundToken = await context.cookies.get(cookieName);
|
|
46
|
+
if (!auth) {
|
|
47
|
+
if (!foundToken) {
|
|
48
|
+
const { jwt, sub } = await mintGuestToken(context.config.siteSecret, ttlSeconds);
|
|
49
|
+
await context.cookies.set({
|
|
50
|
+
name: cookieName,
|
|
51
|
+
value: jwt,
|
|
52
|
+
options: {
|
|
53
|
+
httpOnly: true,
|
|
54
|
+
sameSite: "lax"
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return next({ context: { sessionHeaders: getCartHeaders({
|
|
58
|
+
token: sub,
|
|
59
|
+
connInfo
|
|
60
|
+
}) } });
|
|
61
|
+
}
|
|
62
|
+
const [err, data] = await tryCatch(verifyToken(foundToken, context.config.siteSecret));
|
|
63
|
+
if (err) {
|
|
64
|
+
const { jwt } = await mintGuestToken(context.config.siteSecret, ttlSeconds);
|
|
65
|
+
await context.cookies.set({
|
|
66
|
+
name: cookieName,
|
|
67
|
+
value: jwt,
|
|
68
|
+
options: {
|
|
69
|
+
httpOnly: true,
|
|
70
|
+
sameSite: "lax"
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
throw new KizloError("CART_SESSION_EXPIRED");
|
|
74
|
+
}
|
|
75
|
+
return next({ context: { sessionHeaders: getCartHeaders({
|
|
76
|
+
token: data.sub,
|
|
77
|
+
connInfo
|
|
78
|
+
}) } });
|
|
79
|
+
}
|
|
80
|
+
if (foundToken) {
|
|
81
|
+
const [err, data] = await tryCatch(verifyToken(foundToken, context.config.siteSecret));
|
|
82
|
+
if (!err) {
|
|
83
|
+
const response = await context.service.wordpress.post("/cart/merge", {
|
|
84
|
+
base: WP_KIZLO_BASE,
|
|
85
|
+
headers: getCartHeaders({
|
|
86
|
+
userId: auth.id,
|
|
87
|
+
token: data.sub,
|
|
88
|
+
connInfo
|
|
89
|
+
})
|
|
90
|
+
});
|
|
91
|
+
if (response.error) context.logger.error("CART_MERGE_FAILED", response.error);
|
|
92
|
+
}
|
|
93
|
+
await context.cookies.delete(cookieName);
|
|
94
|
+
}
|
|
95
|
+
return next({ context: { sessionHeaders: getCartHeaders({
|
|
96
|
+
userId: auth.id,
|
|
97
|
+
connInfo
|
|
98
|
+
}) } });
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/cart/error.ts
|
|
104
|
+
const GET_CART_ERROR_MAP = defineErrorMap({});
|
|
105
|
+
const UPDATE_CART_ERROR_MAP = defineErrorMap({});
|
|
106
|
+
const ADD_CART_ITEM_ERROR_MAP = defineErrorMap({
|
|
107
|
+
CART_ITEM_OUT_OF_STOCK: {
|
|
108
|
+
status: 409,
|
|
109
|
+
message: "Product is out of stock."
|
|
110
|
+
},
|
|
111
|
+
CART_ITEM_INSUFFICIENT_STOCK: {
|
|
112
|
+
status: 409,
|
|
113
|
+
message: "Not enough stock for the requested quantity."
|
|
114
|
+
},
|
|
115
|
+
CART_ITEM_NOT_PURCHASABLE: {
|
|
116
|
+
status: 400,
|
|
117
|
+
message: "Product is not purchasable."
|
|
118
|
+
},
|
|
119
|
+
CART_ITEM_INVALID_QUANTITY: {
|
|
120
|
+
status: 400,
|
|
121
|
+
message: "Invalid quantity for the cart item."
|
|
122
|
+
},
|
|
123
|
+
CART_ITEM_EXISTS: {
|
|
124
|
+
status: 409,
|
|
125
|
+
message: "Item already exists in the cart."
|
|
126
|
+
},
|
|
127
|
+
CART_PRODUCT_INVALID: {
|
|
128
|
+
status: 404,
|
|
129
|
+
message: "The requested product is invalid."
|
|
130
|
+
},
|
|
131
|
+
CART_VARIATION_INVALID: {
|
|
132
|
+
status: 400,
|
|
133
|
+
message: "Variation data is invalid or missing."
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
const UPDATE_CART_ITEM_ERROR_MAP = defineErrorMap({
|
|
137
|
+
CART_ITEM_NOT_FOUND: {
|
|
138
|
+
status: 404,
|
|
139
|
+
message: "Cart item not found."
|
|
140
|
+
},
|
|
141
|
+
CART_PRODUCT_INVALID: {
|
|
142
|
+
status: 404,
|
|
143
|
+
message: "The requested product is invalid."
|
|
144
|
+
},
|
|
145
|
+
CART_ITEM_OUT_OF_STOCK: {
|
|
146
|
+
status: 409,
|
|
147
|
+
message: "Product is out of stock."
|
|
148
|
+
},
|
|
149
|
+
CART_ITEM_INSUFFICIENT_STOCK: {
|
|
150
|
+
status: 409,
|
|
151
|
+
message: "Not enough stock for the requested quantity."
|
|
152
|
+
},
|
|
153
|
+
CART_ITEM_INVALID_QUANTITY: {
|
|
154
|
+
status: 400,
|
|
155
|
+
message: "Invalid quantity for the cart item."
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
const REMOVE_CART_ITEM_ERROR_MAP = defineErrorMap({ CART_ITEM_NOT_FOUND: {
|
|
159
|
+
status: 404,
|
|
160
|
+
message: "Cart item not found."
|
|
161
|
+
} });
|
|
162
|
+
const SELECT_SHIPPING_RATE_ERROR_MAP = defineErrorMap({
|
|
163
|
+
CART_SHIPPING_RATE_NOT_FOUND: {
|
|
164
|
+
status: 404,
|
|
165
|
+
message: "The selected shipping rate is no longer available."
|
|
166
|
+
},
|
|
167
|
+
CART_SHIPPING_DISABLED: {
|
|
168
|
+
status: 400,
|
|
169
|
+
message: "Shipping is not available for this cart."
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const APPLY_COUPON_ERROR_MAP = defineErrorMap({
|
|
173
|
+
CART_COUPON_INVALID: {
|
|
174
|
+
status: 400,
|
|
175
|
+
message: "The coupon could not be applied to the cart."
|
|
176
|
+
},
|
|
177
|
+
CART_COUPON_DISABLED: {
|
|
178
|
+
status: 400,
|
|
179
|
+
message: "Coupons are disabled."
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
const REMOVE_COUPON_ERROR_MAP = defineErrorMap({
|
|
183
|
+
CART_COUPON_INVALID: {
|
|
184
|
+
status: 400,
|
|
185
|
+
message: "The coupon could not be removed from the cart."
|
|
186
|
+
},
|
|
187
|
+
CART_COUPON_DISABLED: {
|
|
188
|
+
status: 400,
|
|
189
|
+
message: "Coupons are disabled."
|
|
190
|
+
},
|
|
191
|
+
CART_COUPON_NOT_FOUND: {
|
|
192
|
+
status: 404,
|
|
193
|
+
message: "Coupon was not applied to the cart."
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region src/product/schema.ts
|
|
199
|
+
const SWATCH_TYPES = [
|
|
200
|
+
"text",
|
|
201
|
+
"color",
|
|
202
|
+
"image"
|
|
203
|
+
];
|
|
204
|
+
const SwatchType = z.enum(SWATCH_TYPES);
|
|
205
|
+
const PRODUCT_TYPES = [
|
|
206
|
+
"simple",
|
|
207
|
+
"grouped",
|
|
208
|
+
"external",
|
|
209
|
+
"variable",
|
|
210
|
+
"variation"
|
|
211
|
+
];
|
|
212
|
+
const ProductType = z.enum(PRODUCT_TYPES);
|
|
213
|
+
const ProductTagRef = z.object({
|
|
214
|
+
id: z.number(),
|
|
215
|
+
name: z.string(),
|
|
216
|
+
slug: z.string()
|
|
217
|
+
});
|
|
218
|
+
const ProductBrandRef = z.object({
|
|
219
|
+
id: z.number(),
|
|
220
|
+
name: z.string(),
|
|
221
|
+
slug: z.string()
|
|
222
|
+
});
|
|
223
|
+
const ProductAttributeTermRef = z.object({
|
|
224
|
+
id: z.number(),
|
|
225
|
+
name: z.string(),
|
|
226
|
+
slug: z.string()
|
|
227
|
+
});
|
|
228
|
+
const ProductAttributeRef = z.object({
|
|
229
|
+
id: z.number(),
|
|
230
|
+
name: z.string(),
|
|
231
|
+
taxonomy: z.string(),
|
|
232
|
+
hasVariations: z.boolean(),
|
|
233
|
+
terms: z.array(ProductAttributeTermRef)
|
|
234
|
+
});
|
|
235
|
+
const ProductCategoryRef = z.object({
|
|
236
|
+
id: z.number(),
|
|
237
|
+
name: z.string(),
|
|
238
|
+
slug: z.string()
|
|
239
|
+
});
|
|
240
|
+
const ProductVariationAttributeRef = z.object({
|
|
241
|
+
name: z.string(),
|
|
242
|
+
value: z.string()
|
|
243
|
+
});
|
|
244
|
+
const ProductVariationRef = z.object({
|
|
245
|
+
id: z.number(),
|
|
246
|
+
attributes: z.array(ProductVariationAttributeRef)
|
|
247
|
+
});
|
|
248
|
+
const ProductPrices = z.object({
|
|
249
|
+
price: z.number(),
|
|
250
|
+
salePrice: z.number().nullable(),
|
|
251
|
+
regularPrice: z.number()
|
|
252
|
+
});
|
|
253
|
+
const Product = z.object({
|
|
254
|
+
id: z.number(),
|
|
255
|
+
parentId: z.number(),
|
|
256
|
+
type: ProductType,
|
|
257
|
+
name: z.string(),
|
|
258
|
+
slug: z.string(),
|
|
259
|
+
sku: z.string().nullable(),
|
|
260
|
+
shortDescription: z.string(),
|
|
261
|
+
description: z.string(),
|
|
262
|
+
onSaleFrom: z.number().nullable(),
|
|
263
|
+
onSaleTo: z.number().nullable(),
|
|
264
|
+
isOnSale: z.boolean(),
|
|
265
|
+
prices: ProductPrices,
|
|
266
|
+
averageRating: z.string(),
|
|
267
|
+
reviewCount: z.number(),
|
|
268
|
+
images: z.array(Media),
|
|
269
|
+
categories: z.array(ProductCategoryRef),
|
|
270
|
+
tags: z.array(ProductTagRef),
|
|
271
|
+
brands: z.array(ProductBrandRef),
|
|
272
|
+
attributes: z.array(ProductAttributeRef),
|
|
273
|
+
variations: z.array(ProductVariationRef),
|
|
274
|
+
groupedProducts: z.array(z.number()),
|
|
275
|
+
isSoldIndividually: z.boolean(),
|
|
276
|
+
hasOptions: z.boolean(),
|
|
277
|
+
isPurchasable: z.boolean(),
|
|
278
|
+
isInStock: z.boolean(),
|
|
279
|
+
isOnBackorder: z.boolean(),
|
|
280
|
+
stock: z.number().nullable(),
|
|
281
|
+
lowStockRemaining: z.number().nullable(),
|
|
282
|
+
seo: Seo.nullable(),
|
|
283
|
+
currencyFormat: CurrencyFormat,
|
|
284
|
+
meta: Metadata
|
|
285
|
+
});
|
|
286
|
+
const ProductList = z.object({
|
|
287
|
+
items: z.array(Product),
|
|
288
|
+
meta: ListMetadata
|
|
289
|
+
});
|
|
290
|
+
const RetrieveProductInput = z.object({
|
|
291
|
+
identifier: IdentifierInput,
|
|
292
|
+
previewToken: z.string().optional()
|
|
293
|
+
});
|
|
294
|
+
const PRODUCTS_ORDER_BYS = [
|
|
295
|
+
"date",
|
|
296
|
+
"id",
|
|
297
|
+
"include",
|
|
298
|
+
"title",
|
|
299
|
+
"slug",
|
|
300
|
+
"price",
|
|
301
|
+
"popularity",
|
|
302
|
+
"rating",
|
|
303
|
+
"menu_order",
|
|
304
|
+
"comment_count"
|
|
305
|
+
];
|
|
306
|
+
const ProductOrderBy = z.enum(PRODUCTS_ORDER_BYS);
|
|
307
|
+
const PRODUCT_TAXONOMY_OPERATORS = [
|
|
308
|
+
"in",
|
|
309
|
+
"not_in",
|
|
310
|
+
"and"
|
|
311
|
+
];
|
|
312
|
+
const ProductTaxonomyOperator = z.enum(PRODUCT_TAXONOMY_OPERATORS);
|
|
313
|
+
const PRODUCT_ATTRIBUTE_RELATIONS = ["in", "and"];
|
|
314
|
+
const ProductAttributeRelation = z.enum(PRODUCT_ATTRIBUTE_RELATIONS);
|
|
315
|
+
const PRODUCT_STOCK_STATUSES = [
|
|
316
|
+
"instock",
|
|
317
|
+
"outofstock",
|
|
318
|
+
"onbackorder"
|
|
319
|
+
];
|
|
320
|
+
const ProductStockStatus = z.enum(PRODUCT_STOCK_STATUSES);
|
|
321
|
+
const PRODUCT_CATALOG_VISIBILITIES = [
|
|
322
|
+
"any",
|
|
323
|
+
"visible",
|
|
324
|
+
"catalog",
|
|
325
|
+
"search",
|
|
326
|
+
"hidden"
|
|
327
|
+
];
|
|
328
|
+
const ProductCatalogVisibility = z.enum(PRODUCT_CATALOG_VISIBILITIES);
|
|
329
|
+
const PRODUCT_RATINGS = [
|
|
330
|
+
"1",
|
|
331
|
+
"2",
|
|
332
|
+
"3",
|
|
333
|
+
"4",
|
|
334
|
+
"5"
|
|
335
|
+
];
|
|
336
|
+
const ProductRating = z.enum(PRODUCT_RATINGS);
|
|
337
|
+
const ProductAttributeFilter = z.object({
|
|
338
|
+
attribute: z.string().optional(),
|
|
339
|
+
slug: arrayable(z.string()).optional(),
|
|
340
|
+
termId: arrayable(NumberLike).optional(),
|
|
341
|
+
operator: ProductTaxonomyOperator.optional()
|
|
342
|
+
});
|
|
343
|
+
const ListProductInput = z.object({
|
|
344
|
+
page: NumberLike.optional(),
|
|
345
|
+
perPage: NumberLike.optional(),
|
|
346
|
+
search: z.string().optional(),
|
|
347
|
+
slug: z.string().optional(),
|
|
348
|
+
after: z.string().optional(),
|
|
349
|
+
before: z.string().optional(),
|
|
350
|
+
exclude: arrayable(NumberLike).optional(),
|
|
351
|
+
include: arrayable(NumberLike).optional(),
|
|
352
|
+
offset: NumberLike.optional(),
|
|
353
|
+
order: z.enum(["asc", "desc"]).optional(),
|
|
354
|
+
orderby: ProductOrderBy.optional(),
|
|
355
|
+
parent: arrayable(NumberLike).optional(),
|
|
356
|
+
parentExclude: arrayable(NumberLike).optional(),
|
|
357
|
+
type: ProductType.optional(),
|
|
358
|
+
sku: z.string().optional(),
|
|
359
|
+
featured: BooleanLike.optional(),
|
|
360
|
+
category: z.string().optional(),
|
|
361
|
+
categoryOperator: ProductTaxonomyOperator.optional(),
|
|
362
|
+
brand: z.string().optional(),
|
|
363
|
+
brandOperator: ProductTaxonomyOperator.optional(),
|
|
364
|
+
tag: z.string().optional(),
|
|
365
|
+
tagOperator: ProductTaxonomyOperator.optional(),
|
|
366
|
+
onSale: BooleanLike.optional(),
|
|
367
|
+
minPrice: z.string().optional(),
|
|
368
|
+
maxPrice: z.string().optional(),
|
|
369
|
+
stockStatus: arrayable(ProductStockStatus).optional(),
|
|
370
|
+
attributes: z.array(ProductAttributeFilter).optional(),
|
|
371
|
+
attributeRelation: ProductAttributeRelation.optional(),
|
|
372
|
+
catalogVisibility: ProductCatalogVisibility.optional(),
|
|
373
|
+
rating: arrayable(ProductRating).optional(),
|
|
374
|
+
related: NumberLike.optional()
|
|
375
|
+
});
|
|
376
|
+
const ProductFiltersPriceRange = z.object({
|
|
377
|
+
minPrice: z.number(),
|
|
378
|
+
maxPrice: z.number()
|
|
379
|
+
});
|
|
380
|
+
const ProductFiltersStockStatus = z.object({
|
|
381
|
+
count: z.number(),
|
|
382
|
+
status: ProductStockStatus
|
|
383
|
+
});
|
|
384
|
+
const ProductFiltersTerm = z.object({
|
|
385
|
+
id: z.number(),
|
|
386
|
+
parentId: z.number().nullable(),
|
|
387
|
+
name: z.string(),
|
|
388
|
+
slug: z.string(),
|
|
389
|
+
taxonomy: z.string(),
|
|
390
|
+
description: z.string(),
|
|
391
|
+
count: z.number()
|
|
392
|
+
});
|
|
393
|
+
const ProductFiltersTaxonomyTerm = ProductFiltersTerm.extend({ image: Media.nullable() });
|
|
394
|
+
const ProductFiltersAttributeTerm = ProductFiltersTerm.extend({
|
|
395
|
+
type: SwatchType,
|
|
396
|
+
swatch: z.string().nullable()
|
|
397
|
+
});
|
|
398
|
+
const ProductFilters = z.object({
|
|
399
|
+
priceRange: ProductFiltersPriceRange,
|
|
400
|
+
stockStatuses: z.array(ProductFiltersStockStatus),
|
|
401
|
+
attributeTerms: z.array(ProductFiltersAttributeTerm),
|
|
402
|
+
taxonomyTerms: z.array(ProductFiltersTaxonomyTerm),
|
|
403
|
+
currencyFormat: CurrencyFormat
|
|
404
|
+
});
|
|
405
|
+
const CalculateAttributeFilter = z.object({
|
|
406
|
+
taxonomy: z.string(),
|
|
407
|
+
queryType: z.enum(["or", "and"]).optional()
|
|
408
|
+
});
|
|
409
|
+
const RetrieveProductFiltersInput = ListProductInput.extend({
|
|
410
|
+
ratingFilters: BooleanLike.optional(),
|
|
411
|
+
stockStatusFilters: BooleanLike.optional(),
|
|
412
|
+
taxonomyFilters: z.array(z.string()).optional(),
|
|
413
|
+
attributeFilters: z.array(CalculateAttributeFilter).optional()
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
//#endregion
|
|
417
|
+
//#region src/schema.ts
|
|
418
|
+
const Totals = z$1.object({
|
|
419
|
+
discountTotal: z$1.number(),
|
|
420
|
+
discountTaxTotal: z$1.number(),
|
|
421
|
+
shippingTotal: z$1.number(),
|
|
422
|
+
shippingTaxTotal: z$1.number(),
|
|
423
|
+
feeTotal: z$1.number(),
|
|
424
|
+
feeTaxTotal: z$1.number(),
|
|
425
|
+
taxTotal: z$1.number(),
|
|
426
|
+
total: z$1.number()
|
|
427
|
+
});
|
|
428
|
+
const ItemTotals = z$1.object({
|
|
429
|
+
unitPrice: z$1.number(),
|
|
430
|
+
grossAmount: z$1.number(),
|
|
431
|
+
discountAmount: z$1.number(),
|
|
432
|
+
discountTaxAmount: z$1.number(),
|
|
433
|
+
netAmount: z$1.number(),
|
|
434
|
+
taxAmount: z$1.number(),
|
|
435
|
+
total: z$1.number()
|
|
436
|
+
});
|
|
437
|
+
const ShippingAddress = z$1.object({
|
|
438
|
+
firstName: z$1.string(),
|
|
439
|
+
lastName: z$1.string(),
|
|
440
|
+
phone: z$1.string(),
|
|
441
|
+
company: z$1.string().optional(),
|
|
442
|
+
address1: z$1.string(),
|
|
443
|
+
address2: z$1.string().optional(),
|
|
444
|
+
city: z$1.string(),
|
|
445
|
+
postcode: z$1.string(),
|
|
446
|
+
state: z$1.string(),
|
|
447
|
+
country: z$1.string()
|
|
448
|
+
});
|
|
449
|
+
const BillingAddress = z$1.object({
|
|
450
|
+
firstName: z$1.string(),
|
|
451
|
+
lastName: z$1.string(),
|
|
452
|
+
phone: z$1.string(),
|
|
453
|
+
company: z$1.string().optional(),
|
|
454
|
+
address1: z$1.string(),
|
|
455
|
+
address2: z$1.string().optional(),
|
|
456
|
+
city: z$1.string(),
|
|
457
|
+
postcode: z$1.string(),
|
|
458
|
+
state: z$1.string(),
|
|
459
|
+
country: z$1.string(),
|
|
460
|
+
email: z$1.string()
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
//#endregion
|
|
464
|
+
//#region src/cart/schema.ts
|
|
465
|
+
const CART_ITEM_STATUSES = [
|
|
466
|
+
"insufficient_stock",
|
|
467
|
+
"low_stock",
|
|
468
|
+
"out_of_stock",
|
|
469
|
+
"unavailable",
|
|
470
|
+
"available"
|
|
471
|
+
];
|
|
472
|
+
const CartLineItemStatus = z$1.enum(CART_ITEM_STATUSES);
|
|
473
|
+
const PackageAddress = z$1.object({
|
|
474
|
+
address1: z$1.string(),
|
|
475
|
+
address2: z$1.string(),
|
|
476
|
+
city: z$1.string(),
|
|
477
|
+
state: z$1.string(),
|
|
478
|
+
postcode: z$1.string(),
|
|
479
|
+
country: z$1.string()
|
|
480
|
+
});
|
|
481
|
+
const CartPackageItem = z$1.object({
|
|
482
|
+
key: z$1.string(),
|
|
483
|
+
name: z$1.string(),
|
|
484
|
+
quantity: z$1.number()
|
|
485
|
+
});
|
|
486
|
+
const CartPackageRate = z$1.object({
|
|
487
|
+
id: z$1.string(),
|
|
488
|
+
methodId: z$1.string(),
|
|
489
|
+
name: z$1.string(),
|
|
490
|
+
isSelected: z$1.boolean(),
|
|
491
|
+
description: z$1.string(),
|
|
492
|
+
deliveryTime: z$1.string(),
|
|
493
|
+
amount: z$1.number(),
|
|
494
|
+
taxAmount: z$1.number(),
|
|
495
|
+
total: z$1.number()
|
|
496
|
+
});
|
|
497
|
+
const CartPackageLine = z$1.object({
|
|
498
|
+
id: z$1.number(),
|
|
499
|
+
name: z$1.string(),
|
|
500
|
+
address: PackageAddress,
|
|
501
|
+
items: z$1.array(CartPackageItem),
|
|
502
|
+
rates: z$1.array(CartPackageRate)
|
|
503
|
+
});
|
|
504
|
+
const CartItemVariation = z$1.object({
|
|
505
|
+
name: z$1.string(),
|
|
506
|
+
attribute: z$1.string(),
|
|
507
|
+
value: z$1.string()
|
|
508
|
+
});
|
|
509
|
+
const CartItem = z$1.object({
|
|
510
|
+
key: z$1.string(),
|
|
511
|
+
type: z$1.string(),
|
|
512
|
+
status: CartLineItemStatus,
|
|
513
|
+
productId: z$1.number(),
|
|
514
|
+
variationId: z$1.number().nullable(),
|
|
515
|
+
name: z$1.string(),
|
|
516
|
+
description: z$1.string(),
|
|
517
|
+
shortDescription: z$1.string(),
|
|
518
|
+
sku: z$1.string(),
|
|
519
|
+
slug: z$1.string(),
|
|
520
|
+
lowStockCount: z$1.number().nullable(),
|
|
521
|
+
isSoldIndividually: z$1.boolean(),
|
|
522
|
+
images: z$1.array(Media),
|
|
523
|
+
variations: z$1.array(CartItemVariation),
|
|
524
|
+
prices: ProductPrices,
|
|
525
|
+
quantity: z$1.number(),
|
|
526
|
+
totals: ItemTotals
|
|
527
|
+
});
|
|
528
|
+
const AddCartItemInput = z$1.object({
|
|
529
|
+
productId: z$1.number(),
|
|
530
|
+
quantity: z$1.number(),
|
|
531
|
+
variations: z$1.array(z$1.object({
|
|
532
|
+
attribute: z$1.string(),
|
|
533
|
+
value: z$1.string()
|
|
534
|
+
})).optional()
|
|
535
|
+
});
|
|
536
|
+
const UpdateCartItemInput = z$1.object({
|
|
537
|
+
key: z$1.string(),
|
|
538
|
+
quantity: z$1.number()
|
|
539
|
+
});
|
|
540
|
+
const RemoveCartItemInput = z$1.object({ key: z$1.string() });
|
|
541
|
+
const CartCouponLine = z$1.object({
|
|
542
|
+
id: z$1.string(),
|
|
543
|
+
type: z$1.string(),
|
|
544
|
+
code: z$1.string(),
|
|
545
|
+
amount: z$1.number(),
|
|
546
|
+
taxAmount: z$1.number()
|
|
547
|
+
});
|
|
548
|
+
const ApplyCouponInput = z$1.object({ code: z$1.string() });
|
|
549
|
+
const RemoveCouponInput = z$1.object({ code: z$1.string() });
|
|
550
|
+
const CartShippingLine = z$1.object({
|
|
551
|
+
id: z$1.string(),
|
|
552
|
+
label: z$1.string(),
|
|
553
|
+
amount: z$1.number(),
|
|
554
|
+
taxAmount: z$1.number()
|
|
555
|
+
});
|
|
556
|
+
const CartShippingAddress = ShippingAddress.extend({ id: z$1.string().optional() });
|
|
557
|
+
const CartBillingAddress = BillingAddress.extend({ id: z$1.string().optional() });
|
|
558
|
+
const Cart = z$1.object({
|
|
559
|
+
totalItems: z$1.number(),
|
|
560
|
+
lineItems: z$1.array(CartItem),
|
|
561
|
+
billing: CartBillingAddress.nullable(),
|
|
562
|
+
shipping: CartShippingAddress.nullable(),
|
|
563
|
+
packageLines: z$1.array(CartPackageLine),
|
|
564
|
+
couponLines: z$1.array(CartCouponLine),
|
|
565
|
+
shippingLines: z$1.array(CartShippingLine),
|
|
566
|
+
currencyFormat: CurrencyFormat,
|
|
567
|
+
totals: Totals
|
|
568
|
+
});
|
|
569
|
+
const SelectCartShippingRateInput = z$1.object({
|
|
570
|
+
rateId: z$1.string(),
|
|
571
|
+
packageId: z$1.number()
|
|
572
|
+
});
|
|
573
|
+
const AddressInput = (schema) => {
|
|
574
|
+
return schema.extend({ id: z$1.string().optional() });
|
|
575
|
+
};
|
|
576
|
+
const UpdateCartInput = z$1.object({
|
|
577
|
+
shipping: AddressInput(ShippingAddress).nullable().optional(),
|
|
578
|
+
billing: AddressInput(BillingAddress).nullable().optional()
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
//#endregion
|
|
582
|
+
//#region src/cart/utils.ts
|
|
583
|
+
function deserializeCart(data) {
|
|
584
|
+
const lineItems = data.items.map((item) => {
|
|
585
|
+
const totals = calculateLineItemTotals({
|
|
586
|
+
quantity: item.quantity,
|
|
587
|
+
subtotal: Number(item.totals.line_subtotal),
|
|
588
|
+
subtotal_tax: Number(item.totals.line_subtotal_tax),
|
|
589
|
+
total: Number(item.totals.line_total),
|
|
590
|
+
total_tax: Number(item.totals.line_total_tax)
|
|
591
|
+
});
|
|
592
|
+
let itemStatus = "available";
|
|
593
|
+
const error = data.errors.find((e) => e.message.includes(item.name));
|
|
594
|
+
if (error) switch (error.code) {
|
|
595
|
+
case "woocommerce_rest_product_out_of_stock":
|
|
596
|
+
itemStatus = "out_of_stock";
|
|
597
|
+
break;
|
|
598
|
+
case "woocommerce_rest_cart_item_error":
|
|
599
|
+
itemStatus = "unavailable";
|
|
600
|
+
break;
|
|
601
|
+
}
|
|
602
|
+
if (item.low_stock_remaining) itemStatus = "low_stock";
|
|
603
|
+
const productSlug = new URL(item.permalink).pathname;
|
|
604
|
+
return {
|
|
605
|
+
key: item.key,
|
|
606
|
+
productId: item.id,
|
|
607
|
+
variationId: null,
|
|
608
|
+
type: item.type,
|
|
609
|
+
name: item.name,
|
|
610
|
+
sku: item.sku,
|
|
611
|
+
status: itemStatus,
|
|
612
|
+
quantity: item.quantity,
|
|
613
|
+
isSoldIndividually: item.sold_individually,
|
|
614
|
+
images: item.images.map((item$1) => ({
|
|
615
|
+
id: item$1.id,
|
|
616
|
+
name: item$1.name,
|
|
617
|
+
alt: item$1.alt,
|
|
618
|
+
src: item$1.src
|
|
619
|
+
})),
|
|
620
|
+
variations: item.variation.map((a) => ({
|
|
621
|
+
name: a.attribute,
|
|
622
|
+
attribute: a.raw_attribute,
|
|
623
|
+
value: a.value
|
|
624
|
+
})),
|
|
625
|
+
slug: productSlug,
|
|
626
|
+
description: item.description,
|
|
627
|
+
soldIndividually: item.sold_individually,
|
|
628
|
+
lowStockCount: item.low_stock_remaining,
|
|
629
|
+
prices: {
|
|
630
|
+
price: Number(item.prices.price),
|
|
631
|
+
salePrice: Number(item.prices.sale_price),
|
|
632
|
+
regularPrice: Number(item.prices.regular_price)
|
|
633
|
+
},
|
|
634
|
+
totals,
|
|
635
|
+
shortDescription: item.short_description
|
|
636
|
+
};
|
|
637
|
+
});
|
|
638
|
+
const couponLines = data.coupons.map((coupon) => {
|
|
639
|
+
return {
|
|
640
|
+
id: coupon.code,
|
|
641
|
+
code: coupon.code,
|
|
642
|
+
type: coupon.discount_type,
|
|
643
|
+
amount: Number(coupon.totals.total_discount),
|
|
644
|
+
taxAmount: Number(coupon.totals.total_discount_tax)
|
|
645
|
+
};
|
|
646
|
+
});
|
|
647
|
+
const packageLines = data.shipping_rates.map((pkg) => ({
|
|
648
|
+
id: Number(pkg.package_id),
|
|
649
|
+
name: pkg.name,
|
|
650
|
+
address: {
|
|
651
|
+
address1: pkg.destination.address_1,
|
|
652
|
+
address2: pkg.destination.address_2,
|
|
653
|
+
city: pkg.destination.city,
|
|
654
|
+
state: pkg.destination.state,
|
|
655
|
+
postcode: pkg.destination.postcode,
|
|
656
|
+
country: pkg.destination.country
|
|
657
|
+
},
|
|
658
|
+
items: pkg.items.map((item) => ({
|
|
659
|
+
key: item.key,
|
|
660
|
+
name: item.name,
|
|
661
|
+
quantity: item.quantity
|
|
662
|
+
})),
|
|
663
|
+
rates: pkg.shipping_rates.map((rate) => ({
|
|
664
|
+
id: rate.rate_id,
|
|
665
|
+
name: rate.name,
|
|
666
|
+
description: rate.description,
|
|
667
|
+
deliveryTime: rate.delivery_time,
|
|
668
|
+
amount: Number(rate.price),
|
|
669
|
+
taxAmount: Number(rate.taxes),
|
|
670
|
+
total: Number(rate.price) + Number(rate.taxes),
|
|
671
|
+
isSelected: rate.selected,
|
|
672
|
+
methodId: rate.method_id
|
|
673
|
+
}))
|
|
674
|
+
}));
|
|
675
|
+
const shippingLines = packageLines.reduce((acc, item) => {
|
|
676
|
+
const found = item.rates.find((a) => a.isSelected);
|
|
677
|
+
if (found) acc.push({
|
|
678
|
+
id: found.id,
|
|
679
|
+
label: found.name,
|
|
680
|
+
amount: found.amount,
|
|
681
|
+
taxAmount: found.taxAmount
|
|
682
|
+
});
|
|
683
|
+
return acc;
|
|
684
|
+
}, []);
|
|
685
|
+
const discountTotal = Number(data.totals.total_discount);
|
|
686
|
+
const discountTaxTotal = Number(data.totals.total_discount_tax);
|
|
687
|
+
const shippingTotal = Number(data.totals.total_shipping);
|
|
688
|
+
const shippingTaxTotal = Number(data.totals.total_shipping_tax);
|
|
689
|
+
const feeTotal = Number(data.totals.total_fees);
|
|
690
|
+
const feeTaxTotal = Number(data.totals.total_fees_tax);
|
|
691
|
+
const taxTotal = Number(data.totals.total_tax);
|
|
692
|
+
const total = Number(data.totals.total_price);
|
|
693
|
+
return {
|
|
694
|
+
lineItems,
|
|
695
|
+
couponLines,
|
|
696
|
+
packageLines,
|
|
697
|
+
shippingLines,
|
|
698
|
+
totalItems: data.items_count,
|
|
699
|
+
billing: data.billing_address.address_1.length ? deserializeCartBillingAddress(data) : null,
|
|
700
|
+
shipping: data.shipping_address.address_1.length ? deserializeCartShippingAddress(data) : null,
|
|
701
|
+
currencyFormat: deserializeCurrencyFormat(data.totals),
|
|
702
|
+
totals: {
|
|
703
|
+
discountTotal,
|
|
704
|
+
discountTaxTotal,
|
|
705
|
+
shippingTotal,
|
|
706
|
+
shippingTaxTotal,
|
|
707
|
+
feeTotal,
|
|
708
|
+
feeTaxTotal,
|
|
709
|
+
taxTotal,
|
|
710
|
+
total
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
function deserializeCartShippingAddress(cart) {
|
|
715
|
+
return {
|
|
716
|
+
address1: cart.shipping_address.address_1,
|
|
717
|
+
address2: cart.shipping_address.address_2,
|
|
718
|
+
city: cart.shipping_address.city,
|
|
719
|
+
company: cart.shipping_address.company,
|
|
720
|
+
country: cart.shipping_address.country,
|
|
721
|
+
firstName: cart.shipping_address.first_name,
|
|
722
|
+
lastName: cart.shipping_address.last_name,
|
|
723
|
+
phone: cart.shipping_address.phone,
|
|
724
|
+
postcode: cart.shipping_address.postcode,
|
|
725
|
+
state: cart.shipping_address.state
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
function deserializeCartBillingAddress(cart) {
|
|
729
|
+
return {
|
|
730
|
+
address1: cart.billing_address.address_1,
|
|
731
|
+
address2: cart.billing_address.address_2,
|
|
732
|
+
city: cart.billing_address.city,
|
|
733
|
+
company: cart.billing_address.company,
|
|
734
|
+
country: cart.billing_address.country,
|
|
735
|
+
firstName: cart.billing_address.first_name,
|
|
736
|
+
lastName: cart.billing_address.last_name,
|
|
737
|
+
phone: cart.billing_address.phone,
|
|
738
|
+
postcode: cart.billing_address.postcode,
|
|
739
|
+
state: cart.billing_address.state,
|
|
740
|
+
email: cart.billing_address.email
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
function calculateLineItemTotals(input) {
|
|
744
|
+
const unitPrice = input.subtotal / input.quantity;
|
|
745
|
+
const grossAmount = input.subtotal;
|
|
746
|
+
return {
|
|
747
|
+
unitPrice,
|
|
748
|
+
discountAmount: input.subtotal - input.total,
|
|
749
|
+
discountTaxAmount: input.subtotal_tax - input.total_tax,
|
|
750
|
+
grossAmount,
|
|
751
|
+
netAmount: input.total,
|
|
752
|
+
taxAmount: input.total_tax,
|
|
753
|
+
total: input.total + input.total_tax
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
//#endregion
|
|
758
|
+
//#region src/cart/index.ts
|
|
759
|
+
const CART_ROUTER = {
|
|
760
|
+
get: createProcedure({
|
|
761
|
+
scope: "api",
|
|
762
|
+
method: "GET",
|
|
763
|
+
path: "/cart",
|
|
764
|
+
output: Cart.nullable(),
|
|
765
|
+
errors: GET_CART_ERROR_MAP,
|
|
766
|
+
middlewares: [sessionMiddleware()]
|
|
767
|
+
}, async ({ context, errors }) => {
|
|
768
|
+
const response = await context.service.wordpress.get("/cart", {
|
|
769
|
+
base: WC_STORE_BASE,
|
|
770
|
+
headers: context.sessionHeaders
|
|
771
|
+
});
|
|
772
|
+
if (response.error) switch (response.error.code) {
|
|
773
|
+
default:
|
|
774
|
+
context.logger.error("Get cart unhandled error", response.error, { code: response.error.code });
|
|
775
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
776
|
+
}
|
|
777
|
+
return deserializeCart(response.data);
|
|
778
|
+
}),
|
|
779
|
+
update: createProcedure({
|
|
780
|
+
scope: "api",
|
|
781
|
+
method: "PUT",
|
|
782
|
+
path: "/cart",
|
|
783
|
+
output: Cart,
|
|
784
|
+
body: UpdateCartInput,
|
|
785
|
+
errors: UPDATE_CART_ERROR_MAP,
|
|
786
|
+
middlewares: [sessionMiddleware()]
|
|
787
|
+
}, async ({ context, input: { body: input }, errors }) => {
|
|
788
|
+
const connInfo = await context.getConnInfo();
|
|
789
|
+
const defaultBilling = input.billing ?? {
|
|
790
|
+
...input.shipping,
|
|
791
|
+
email: void 0
|
|
792
|
+
};
|
|
793
|
+
const updateData = {
|
|
794
|
+
billing_address: defaultBilling !== void 0 ? {
|
|
795
|
+
first_name: defaultBilling?.firstName ?? "",
|
|
796
|
+
last_name: defaultBilling?.lastName ?? "",
|
|
797
|
+
address_1: defaultBilling?.address1 ?? "",
|
|
798
|
+
address_2: defaultBilling?.address2 ?? "",
|
|
799
|
+
company: defaultBilling?.company ?? "",
|
|
800
|
+
email: defaultBilling?.email ?? "",
|
|
801
|
+
phone: defaultBilling?.phone ?? "",
|
|
802
|
+
city: defaultBilling?.city ?? "",
|
|
803
|
+
state: defaultBilling?.state ?? connInfo?.state ?? void 0,
|
|
804
|
+
country: defaultBilling?.country ?? connInfo?.country ?? void 0,
|
|
805
|
+
postcode: defaultBilling?.postcode ?? connInfo?.postcode ?? ""
|
|
806
|
+
} : {},
|
|
807
|
+
shipping_address: input.shipping !== void 0 ? {
|
|
808
|
+
first_name: input.shipping?.firstName ?? "",
|
|
809
|
+
last_name: input.shipping?.lastName ?? "",
|
|
810
|
+
address_1: input.shipping?.address1 ?? "",
|
|
811
|
+
address_2: input.shipping?.address2 ?? "",
|
|
812
|
+
company: input.shipping?.company ?? "",
|
|
813
|
+
phone: input.shipping?.phone ?? "",
|
|
814
|
+
city: input.shipping?.city ?? "",
|
|
815
|
+
state: input.shipping?.state ?? connInfo?.state ?? void 0,
|
|
816
|
+
country: input.shipping?.country ?? connInfo?.country ?? void 0,
|
|
817
|
+
postcode: input.shipping?.postcode ?? connInfo?.postcode ?? ""
|
|
818
|
+
} : {}
|
|
819
|
+
};
|
|
820
|
+
const response = await context.service.wordpress.post("/cart/update-customer", {
|
|
821
|
+
base: WC_STORE_BASE,
|
|
822
|
+
body: {
|
|
823
|
+
billing_address: updateData.billing_address,
|
|
824
|
+
shipping_address: updateData.shipping_address
|
|
825
|
+
},
|
|
826
|
+
headers: context.sessionHeaders
|
|
827
|
+
});
|
|
828
|
+
if (response.error) switch (response.error.code) {
|
|
829
|
+
default:
|
|
830
|
+
context.logger.error("Update cart customer unhandled error", response.error, { code: response.error.code });
|
|
831
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
832
|
+
}
|
|
833
|
+
return deserializeCart(response.data);
|
|
834
|
+
}),
|
|
835
|
+
selectShippingRate: createProcedure({
|
|
836
|
+
scope: "api",
|
|
837
|
+
method: "PUT",
|
|
838
|
+
path: "/cart/shipping-rate",
|
|
839
|
+
body: SelectCartShippingRateInput,
|
|
840
|
+
output: Cart,
|
|
841
|
+
errors: SELECT_SHIPPING_RATE_ERROR_MAP,
|
|
842
|
+
middlewares: [sessionMiddleware()]
|
|
843
|
+
}, async ({ context, input: { body }, errors }) => {
|
|
844
|
+
const response = await context.service.wordpress.post("/cart/select-shipping-rate", {
|
|
845
|
+
base: WC_STORE_BASE,
|
|
846
|
+
headers: context.sessionHeaders,
|
|
847
|
+
body: {
|
|
848
|
+
rate_id: body.rateId,
|
|
849
|
+
package_id: body.packageId
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
if (response.error) switch (response.error.code) {
|
|
853
|
+
case "woocommerce_rest_cart_shipping_rate_not_found": throw errors.CART_SHIPPING_RATE_NOT_FOUND({ message: response.error.message });
|
|
854
|
+
case "woocommerce_rest_shipping_disabled": throw errors.CART_SHIPPING_DISABLED({ message: response.error.message });
|
|
855
|
+
default:
|
|
856
|
+
context.logger.error("Select shipping rate unhandled error", response.error, { code: response.error.code });
|
|
857
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
858
|
+
}
|
|
859
|
+
return deserializeCart(response.data);
|
|
860
|
+
}),
|
|
861
|
+
items: {
|
|
862
|
+
add: createProcedure({
|
|
863
|
+
scope: "api",
|
|
864
|
+
method: "POST",
|
|
865
|
+
path: "/cart/items",
|
|
866
|
+
body: AddCartItemInput,
|
|
867
|
+
output: Cart,
|
|
868
|
+
errors: ADD_CART_ITEM_ERROR_MAP,
|
|
869
|
+
middlewares: [sessionMiddleware()]
|
|
870
|
+
}, async ({ context, input: { body: input }, errors }) => {
|
|
871
|
+
const response = await context.service.wordpress.post("/cart/add-item", {
|
|
872
|
+
body: {
|
|
873
|
+
id: input.productId,
|
|
874
|
+
quantity: input.quantity,
|
|
875
|
+
variation: input.variations ?? []
|
|
876
|
+
},
|
|
877
|
+
base: WC_STORE_BASE,
|
|
878
|
+
headers: context.sessionHeaders
|
|
879
|
+
});
|
|
880
|
+
if (response.error) switch (response.error.code) {
|
|
881
|
+
case "woocommerce_rest_product_out_of_stock": throw errors.CART_ITEM_OUT_OF_STOCK({ message: response.error.message });
|
|
882
|
+
case "woocommerce_rest_product_partially_out_of_stock": throw errors.CART_ITEM_INSUFFICIENT_STOCK({ message: response.error.message });
|
|
883
|
+
case "woocommerce_rest_product_not_purchasable": throw errors.CART_ITEM_NOT_PURCHASABLE({ message: response.error.message });
|
|
884
|
+
case "woocommerce_rest_product_invalid_quantity": throw errors.CART_ITEM_INVALID_QUANTITY({ message: response.error.message });
|
|
885
|
+
case "woocommerce_rest_cart_item_exists": throw errors.CART_ITEM_EXISTS({ message: response.error.message });
|
|
886
|
+
case "woocommerce_rest_cart_invalid_product":
|
|
887
|
+
case "woocommerce_rest_cart_invalid_parent_product": throw errors.CART_PRODUCT_INVALID({ message: response.error.message });
|
|
888
|
+
case "woocommerce_rest_invalid_variation_data":
|
|
889
|
+
case "woocommerce_rest_missing_attributes":
|
|
890
|
+
case "woocommerce_rest_missing_variation_data":
|
|
891
|
+
case "woocommerce_rest_variation_id_from_variation_data": throw errors.CART_VARIATION_INVALID({ message: response.error.message });
|
|
892
|
+
default:
|
|
893
|
+
context.logger.error("Add cart item unhandled error", response.error, { code: response.error.code });
|
|
894
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
895
|
+
}
|
|
896
|
+
return deserializeCart(response.data);
|
|
897
|
+
}),
|
|
898
|
+
update: createProcedure({
|
|
899
|
+
scope: "api",
|
|
900
|
+
method: "PUT",
|
|
901
|
+
path: "/cart/items/{key}",
|
|
902
|
+
params: UpdateCartItemInput.pick({ key: true }),
|
|
903
|
+
body: UpdateCartItemInput.pick({ quantity: true }),
|
|
904
|
+
output: Cart,
|
|
905
|
+
errors: UPDATE_CART_ITEM_ERROR_MAP,
|
|
906
|
+
middlewares: [sessionMiddleware()]
|
|
907
|
+
}, async ({ context, input: { params, body }, errors }) => {
|
|
908
|
+
const response = await context.service.wordpress.post("/cart/update-item", {
|
|
909
|
+
body: {
|
|
910
|
+
key: params.key,
|
|
911
|
+
quantity: body.quantity
|
|
912
|
+
},
|
|
913
|
+
base: WC_STORE_BASE,
|
|
914
|
+
headers: context.sessionHeaders
|
|
915
|
+
});
|
|
916
|
+
if (response.error) switch (response.error.code) {
|
|
917
|
+
case "woocommerce_rest_cart_invalid_key": throw errors.CART_ITEM_NOT_FOUND({ message: response.error.message });
|
|
918
|
+
case "woocommerce_rest_cart_invalid_product": throw errors.CART_PRODUCT_INVALID({ message: response.error.message });
|
|
919
|
+
case "woocommerce_rest_product_out_of_stock": throw errors.CART_ITEM_OUT_OF_STOCK({ message: response.error.message });
|
|
920
|
+
case "woocommerce_rest_product_partially_out_of_stock": throw errors.CART_ITEM_INSUFFICIENT_STOCK({ message: response.error.message });
|
|
921
|
+
case "woocommerce_rest_product_invalid_quantity": throw errors.CART_ITEM_INVALID_QUANTITY({ message: response.error.message });
|
|
922
|
+
default:
|
|
923
|
+
context.logger.error("Update cart item unhandled error", response.error, { code: response.error.code });
|
|
924
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
925
|
+
}
|
|
926
|
+
return deserializeCart(response.data);
|
|
927
|
+
}),
|
|
928
|
+
remove: createProcedure({
|
|
929
|
+
scope: "api",
|
|
930
|
+
method: "PATCH",
|
|
931
|
+
path: "/cart/items/{key}",
|
|
932
|
+
params: RemoveCartItemInput.pick({ key: true }),
|
|
933
|
+
output: Cart,
|
|
934
|
+
errors: REMOVE_CART_ITEM_ERROR_MAP,
|
|
935
|
+
middlewares: [sessionMiddleware()]
|
|
936
|
+
}, async ({ context, input: { params }, errors }) => {
|
|
937
|
+
const response = await context.service.wordpress.post("/cart/remove-item", {
|
|
938
|
+
body: { key: params.key },
|
|
939
|
+
base: WC_STORE_BASE,
|
|
940
|
+
headers: context.sessionHeaders
|
|
941
|
+
});
|
|
942
|
+
if (response.error) switch (response.error.code) {
|
|
943
|
+
case "woocommerce_rest_cart_invalid_key": throw errors.CART_ITEM_NOT_FOUND({ message: response.error.message });
|
|
944
|
+
default:
|
|
945
|
+
context.logger.error("Remove cart item unhandled error", response.error, { code: response.error.code });
|
|
946
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
947
|
+
}
|
|
948
|
+
return deserializeCart(response.data);
|
|
949
|
+
})
|
|
950
|
+
},
|
|
951
|
+
coupons: {
|
|
952
|
+
apply: createProcedure({
|
|
953
|
+
scope: "api",
|
|
954
|
+
method: "POST",
|
|
955
|
+
path: "/cart/coupons",
|
|
956
|
+
body: ApplyCouponInput,
|
|
957
|
+
output: Cart,
|
|
958
|
+
errors: APPLY_COUPON_ERROR_MAP,
|
|
959
|
+
middlewares: [sessionMiddleware()]
|
|
960
|
+
}, async ({ context, input: { body }, errors }) => {
|
|
961
|
+
const response = await context.service.wordpress.post("/cart/apply-coupon", {
|
|
962
|
+
body: { code: body.code },
|
|
963
|
+
base: WC_STORE_BASE,
|
|
964
|
+
headers: context.sessionHeaders
|
|
965
|
+
});
|
|
966
|
+
if (response.error) switch (response.error.code) {
|
|
967
|
+
case "woocommerce_rest_cart_coupon_error": throw errors.CART_COUPON_INVALID({ message: response.error.message });
|
|
968
|
+
case "woocommerce_rest_cart_coupon_disabled": throw errors.CART_COUPON_DISABLED({ message: response.error.message });
|
|
969
|
+
default:
|
|
970
|
+
context.logger.error("Apply coupon unhandled error", response.error, { code: response.error.code });
|
|
971
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
972
|
+
}
|
|
973
|
+
return deserializeCart(response.data);
|
|
974
|
+
}),
|
|
975
|
+
remove: createProcedure({
|
|
976
|
+
scope: "api",
|
|
977
|
+
method: "POST",
|
|
978
|
+
path: "/cart/coupons/{code}",
|
|
979
|
+
params: RemoveCouponInput.pick({ code: true }),
|
|
980
|
+
output: Cart,
|
|
981
|
+
errors: REMOVE_COUPON_ERROR_MAP,
|
|
982
|
+
middlewares: [sessionMiddleware()]
|
|
983
|
+
}, async ({ context, input, errors }) => {
|
|
984
|
+
const response = await context.service.wordpress.post("/cart/remove-coupon", {
|
|
985
|
+
body: { code: input.params.code },
|
|
986
|
+
base: WC_STORE_BASE,
|
|
987
|
+
headers: context.sessionHeaders
|
|
988
|
+
});
|
|
989
|
+
if (response.error) switch (response.error.code) {
|
|
990
|
+
case "woocommerce_rest_cart_coupon_error": throw errors.CART_COUPON_INVALID({ message: response.error.message });
|
|
991
|
+
case "woocommerce_rest_cart_coupon_disabled": throw errors.CART_COUPON_DISABLED({ message: response.error.message });
|
|
992
|
+
case "woocommerce_rest_cart_coupon_invalid_code": throw errors.CART_COUPON_NOT_FOUND({ message: response.error.message });
|
|
993
|
+
default:
|
|
994
|
+
context.logger.error("Remove coupon unhandled error", response.error, { code: response.error.code });
|
|
995
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
996
|
+
}
|
|
997
|
+
return deserializeCart(response.data);
|
|
998
|
+
})
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
|
|
1002
|
+
//#endregion
|
|
1003
|
+
//#region src/checkout/error.ts
|
|
1004
|
+
const GET_CHECKOUT_ERROR_MAP = defineErrorMap({ CHECKOUT_ORDER_NOT_FOUND: {
|
|
1005
|
+
status: 404,
|
|
1006
|
+
message: "No checkout order found."
|
|
1007
|
+
} });
|
|
1008
|
+
const CONFIRM_CHECKOUT_ERROR_MAP = defineErrorMap({
|
|
1009
|
+
CHECKOUT_ADDRESS_COUNTRY_INVALID: {
|
|
1010
|
+
status: 400,
|
|
1011
|
+
message: "The address country is not supported."
|
|
1012
|
+
},
|
|
1013
|
+
CHECKOUT_ADDRESS_INVALID: {
|
|
1014
|
+
status: 400,
|
|
1015
|
+
message: "The provided address is invalid."
|
|
1016
|
+
},
|
|
1017
|
+
CHECKOUT_COUPON_INVALID: {
|
|
1018
|
+
status: 400,
|
|
1019
|
+
message: "A coupon on the cart is no longer valid."
|
|
1020
|
+
},
|
|
1021
|
+
CHECKOUT_EMAIL_INVALID: {
|
|
1022
|
+
status: 400,
|
|
1023
|
+
message: "The provided email address is invalid."
|
|
1024
|
+
},
|
|
1025
|
+
CHECKOUT_EMAIL_MISSING: {
|
|
1026
|
+
status: 400,
|
|
1027
|
+
message: "An email address is required."
|
|
1028
|
+
},
|
|
1029
|
+
CHECKOUT_PAYMENT_FAILED: {
|
|
1030
|
+
status: 400,
|
|
1031
|
+
message: "Payment could not be processed."
|
|
1032
|
+
},
|
|
1033
|
+
CHECKOUT_PAYMENT_METHOD_DISABLED: {
|
|
1034
|
+
status: 400,
|
|
1035
|
+
message: "The selected payment method is not available."
|
|
1036
|
+
},
|
|
1037
|
+
CHECKOUT_PAYMENT_METHOD_MISSING: {
|
|
1038
|
+
status: 400,
|
|
1039
|
+
message: "A payment method is required."
|
|
1040
|
+
},
|
|
1041
|
+
CHECKOUT_VALIDATION_FAILED: {
|
|
1042
|
+
status: 400,
|
|
1043
|
+
message: "Checkout validation failed."
|
|
1044
|
+
},
|
|
1045
|
+
CHECKOUT_GUEST_DISABLED: {
|
|
1046
|
+
status: 403,
|
|
1047
|
+
message: "Guest checkout is not allowed."
|
|
1048
|
+
},
|
|
1049
|
+
CHECKOUT_ORDER_NOT_FOUND: {
|
|
1050
|
+
status: 404,
|
|
1051
|
+
message: "No checkout order found."
|
|
1052
|
+
},
|
|
1053
|
+
CHECKOUT_CART_EMPTY: {
|
|
1054
|
+
status: 409,
|
|
1055
|
+
message: "The cart is empty."
|
|
1056
|
+
},
|
|
1057
|
+
CHECKOUT_CART_INVALID: {
|
|
1058
|
+
status: 409,
|
|
1059
|
+
message: "An item in the cart is no longer valid."
|
|
1060
|
+
},
|
|
1061
|
+
CHECKOUT_COUPONS_REMOVED: {
|
|
1062
|
+
status: 409,
|
|
1063
|
+
message: "One or more coupons were removed from the cart."
|
|
1064
|
+
},
|
|
1065
|
+
CHECKOUT_COUPON_RESERVATION_FAILED: {
|
|
1066
|
+
status: 409,
|
|
1067
|
+
message: "A coupon could not be reserved for this order."
|
|
1068
|
+
},
|
|
1069
|
+
CHECKOUT_PRODUCT_INSUFFICIENT_STOCK: {
|
|
1070
|
+
status: 409,
|
|
1071
|
+
message: "Not enough stock for one or more items in the cart."
|
|
1072
|
+
},
|
|
1073
|
+
CHECKOUT_PRODUCT_NOT_PURCHASABLE: {
|
|
1074
|
+
status: 409,
|
|
1075
|
+
message: "An item in the cart is no longer purchasable."
|
|
1076
|
+
},
|
|
1077
|
+
CHECKOUT_PRODUCT_OUT_OF_STOCK: {
|
|
1078
|
+
status: 409,
|
|
1079
|
+
message: "An item in the cart is out of stock."
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
const RETRY_CHECKOUT_ERROR_MAP = defineErrorMap({
|
|
1083
|
+
CHECKOUT_EMAIL_INVALID: {
|
|
1084
|
+
status: 400,
|
|
1085
|
+
message: "The billing email is invalid."
|
|
1086
|
+
},
|
|
1087
|
+
CHECKOUT_PAYMENT_FAILED: {
|
|
1088
|
+
status: 400,
|
|
1089
|
+
message: "Payment could not be processed."
|
|
1090
|
+
},
|
|
1091
|
+
CHECKOUT_PAYMENT_METHOD_DISABLED: {
|
|
1092
|
+
status: 400,
|
|
1093
|
+
message: "The selected payment method is not available."
|
|
1094
|
+
},
|
|
1095
|
+
CHECKOUT_PAYMENT_METHOD_MISSING: {
|
|
1096
|
+
status: 400,
|
|
1097
|
+
message: "A payment method is required."
|
|
1098
|
+
},
|
|
1099
|
+
CHECKOUT_ORDER_FORBIDDEN: {
|
|
1100
|
+
status: 403,
|
|
1101
|
+
message: "You are not allowed to pay for this order."
|
|
1102
|
+
},
|
|
1103
|
+
CHECKOUT_ORDER_NOT_FOUND: {
|
|
1104
|
+
status: 404,
|
|
1105
|
+
message: "Order not found."
|
|
1106
|
+
},
|
|
1107
|
+
CHECKOUT_ORDER_STATUS_INVALID: {
|
|
1108
|
+
status: 409,
|
|
1109
|
+
message: "This order is not in a state that can be paid."
|
|
1110
|
+
}
|
|
1111
|
+
});
|
|
1112
|
+
const UPDATE_CHECKOUT_ERROR_MAP = defineErrorMap({
|
|
1113
|
+
CHECKOUT_COUPON_INVALID: {
|
|
1114
|
+
status: 400,
|
|
1115
|
+
message: "A coupon on the cart is no longer valid."
|
|
1116
|
+
},
|
|
1117
|
+
CHECKOUT_PAYMENT_METHOD_DISABLED: {
|
|
1118
|
+
status: 400,
|
|
1119
|
+
message: "The selected payment method is not available."
|
|
1120
|
+
},
|
|
1121
|
+
CHECKOUT_ORDER_NOT_FOUND: {
|
|
1122
|
+
status: 404,
|
|
1123
|
+
message: "No checkout order found."
|
|
1124
|
+
},
|
|
1125
|
+
CHECKOUT_CART_EMPTY: {
|
|
1126
|
+
status: 409,
|
|
1127
|
+
message: "The cart is empty."
|
|
1128
|
+
},
|
|
1129
|
+
CHECKOUT_CART_INVALID: {
|
|
1130
|
+
status: 409,
|
|
1131
|
+
message: "An item in the cart is no longer valid."
|
|
1132
|
+
},
|
|
1133
|
+
CHECKOUT_PRODUCT_INSUFFICIENT_STOCK: {
|
|
1134
|
+
status: 409,
|
|
1135
|
+
message: "Not enough stock for one or more items in the cart."
|
|
1136
|
+
},
|
|
1137
|
+
CHECKOUT_PRODUCT_NOT_PURCHASABLE: {
|
|
1138
|
+
status: 409,
|
|
1139
|
+
message: "An item in the cart is no longer purchasable."
|
|
1140
|
+
},
|
|
1141
|
+
CHECKOUT_PRODUCT_OUT_OF_STOCK: {
|
|
1142
|
+
status: 409,
|
|
1143
|
+
message: "An item in the cart is out of stock."
|
|
1144
|
+
}
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
//#endregion
|
|
1148
|
+
//#region src/checkout/schema.ts
|
|
1149
|
+
const CheckoutAdditionalFields = z$2.record(z$2.string(), z$2.union([z$2.string(), z$2.boolean()]));
|
|
1150
|
+
const CheckoutPaymentData = z$2.array(z$2.object({
|
|
1151
|
+
key: z$2.string(),
|
|
1152
|
+
value: z$2.union([z$2.string(), z$2.boolean()])
|
|
1153
|
+
}));
|
|
1154
|
+
const Checkout = z$2.object({
|
|
1155
|
+
cart: Cart.nullable(),
|
|
1156
|
+
billingAddress: BillingAddress,
|
|
1157
|
+
shippingAddress: ShippingAddress,
|
|
1158
|
+
paymentMethod: z$2.string(),
|
|
1159
|
+
customerNote: z$2.string(),
|
|
1160
|
+
additionalFields: CheckoutAdditionalFields,
|
|
1161
|
+
paymentResult: z$2.object({
|
|
1162
|
+
status: z$2.enum([
|
|
1163
|
+
"success",
|
|
1164
|
+
"pending",
|
|
1165
|
+
"failure",
|
|
1166
|
+
"error"
|
|
1167
|
+
]),
|
|
1168
|
+
data: z$2.array(z$2.object({
|
|
1169
|
+
key: z$2.string(),
|
|
1170
|
+
value: z$2.string()
|
|
1171
|
+
})).optional(),
|
|
1172
|
+
redirectUrl: z$2.string()
|
|
1173
|
+
}).nullable()
|
|
1174
|
+
});
|
|
1175
|
+
const UpdateCheckoutInput = z$2.object({
|
|
1176
|
+
paymentMethod: z$2.string().optional(),
|
|
1177
|
+
customerNote: z$2.string().optional(),
|
|
1178
|
+
recalculateTotals: z$2.boolean().optional(),
|
|
1179
|
+
additionalFields: CheckoutAdditionalFields.optional()
|
|
1180
|
+
});
|
|
1181
|
+
const ConfirmCheckoutInput = z$2.object({
|
|
1182
|
+
customerPassword: z$2.string().optional(),
|
|
1183
|
+
paymentData: CheckoutPaymentData.optional()
|
|
1184
|
+
});
|
|
1185
|
+
const RetryCheckoutInput = z$2.object({
|
|
1186
|
+
key: z$2.string(),
|
|
1187
|
+
orderId: NumberLike,
|
|
1188
|
+
paymentMethod: z$2.string(),
|
|
1189
|
+
billingEmail: z$2.email().optional(),
|
|
1190
|
+
billingAddress: BillingAddress.optional(),
|
|
1191
|
+
paymentData: CheckoutPaymentData.optional(),
|
|
1192
|
+
shippingAddress: ShippingAddress.optional()
|
|
1193
|
+
});
|
|
1194
|
+
|
|
1195
|
+
//#endregion
|
|
1196
|
+
//#region src/checkout/utils.ts
|
|
1197
|
+
function deserializeCheckout(data) {
|
|
1198
|
+
return {
|
|
1199
|
+
cart: data.__experimentalCart ? deserializeCart(data.__experimentalCart) : null,
|
|
1200
|
+
shippingAddress: {
|
|
1201
|
+
address1: data.shipping_address.address_1,
|
|
1202
|
+
address2: data.shipping_address.address_2,
|
|
1203
|
+
city: data.shipping_address.city,
|
|
1204
|
+
company: data.shipping_address.company,
|
|
1205
|
+
country: data.shipping_address.country,
|
|
1206
|
+
firstName: data.shipping_address.first_name,
|
|
1207
|
+
lastName: data.shipping_address.last_name,
|
|
1208
|
+
phone: data.shipping_address.phone,
|
|
1209
|
+
postcode: data.shipping_address.postcode,
|
|
1210
|
+
state: data.shipping_address.state
|
|
1211
|
+
},
|
|
1212
|
+
billingAddress: {
|
|
1213
|
+
address1: data.billing_address.address_1,
|
|
1214
|
+
address2: data.billing_address.address_2,
|
|
1215
|
+
city: data.billing_address.city,
|
|
1216
|
+
company: data.billing_address.company,
|
|
1217
|
+
country: data.billing_address.country,
|
|
1218
|
+
email: data.billing_address.email,
|
|
1219
|
+
firstName: data.billing_address.first_name,
|
|
1220
|
+
lastName: data.billing_address.last_name,
|
|
1221
|
+
phone: data.billing_address.phone,
|
|
1222
|
+
postcode: data.billing_address.postcode,
|
|
1223
|
+
state: data.billing_address.state
|
|
1224
|
+
},
|
|
1225
|
+
additionalFields: data.additional_fields,
|
|
1226
|
+
customerNote: data.customer_note,
|
|
1227
|
+
paymentMethod: data.payment_method,
|
|
1228
|
+
paymentResult: data.payment_result?.payment_status ? {
|
|
1229
|
+
status: data.payment_result.payment_status,
|
|
1230
|
+
redirectUrl: data.payment_result.redirect_url,
|
|
1231
|
+
data: data.payment_result.payment_details
|
|
1232
|
+
} : null
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
//#endregion
|
|
1237
|
+
//#region src/checkout/index.ts
|
|
1238
|
+
const CHECKOUT_ROUTER = {
|
|
1239
|
+
get: createProcedure({
|
|
1240
|
+
scope: "api",
|
|
1241
|
+
method: "GET",
|
|
1242
|
+
path: "/checkout",
|
|
1243
|
+
output: Checkout,
|
|
1244
|
+
errors: GET_CHECKOUT_ERROR_MAP,
|
|
1245
|
+
middlewares: [sessionMiddleware()]
|
|
1246
|
+
}, async ({ context, errors }) => {
|
|
1247
|
+
const response = await context.service.wordpress.get("/checkout", {
|
|
1248
|
+
base: WC_STORE_BASE,
|
|
1249
|
+
headers: context.sessionHeaders
|
|
1250
|
+
});
|
|
1251
|
+
if (response.error) switch (response.error.code) {
|
|
1252
|
+
case "woocommerce_rest_checkout_missing_order": throw errors.CHECKOUT_ORDER_NOT_FOUND({ message: response.error.message });
|
|
1253
|
+
default:
|
|
1254
|
+
context.logger.error("Get checkout unhandled error", response.error, { code: response.error.code });
|
|
1255
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
1256
|
+
}
|
|
1257
|
+
return deserializeCheckout(response.data);
|
|
1258
|
+
}),
|
|
1259
|
+
update: createProcedure({
|
|
1260
|
+
scope: "api",
|
|
1261
|
+
method: "PUT",
|
|
1262
|
+
path: "/checkout",
|
|
1263
|
+
body: UpdateCheckoutInput,
|
|
1264
|
+
output: Checkout,
|
|
1265
|
+
errors: UPDATE_CHECKOUT_ERROR_MAP,
|
|
1266
|
+
middlewares: [sessionMiddleware()]
|
|
1267
|
+
}, async ({ context, input, errors }) => {
|
|
1268
|
+
const response = await context.service.wordpress.put("/checkout", {
|
|
1269
|
+
base: WC_STORE_BASE,
|
|
1270
|
+
body: {
|
|
1271
|
+
order_notes: input.body.customerNote,
|
|
1272
|
+
payment_method: input.body.paymentMethod,
|
|
1273
|
+
additional_fields: input.body.additionalFields,
|
|
1274
|
+
__experimental_calc_totals: input.body.recalculateTotals
|
|
1275
|
+
},
|
|
1276
|
+
headers: context.sessionHeaders
|
|
1277
|
+
});
|
|
1278
|
+
if (response.error) switch (response.error.code) {
|
|
1279
|
+
case "woocommerce_rest_cart_coupon_error": throw errors.CHECKOUT_COUPON_INVALID({ message: response.error.message });
|
|
1280
|
+
case "woocommerce_rest_checkout_payment_method_disabled": throw errors.CHECKOUT_PAYMENT_METHOD_DISABLED({ message: response.error.message });
|
|
1281
|
+
case "woocommerce_rest_checkout_missing_order": throw errors.CHECKOUT_ORDER_NOT_FOUND({ message: response.error.message });
|
|
1282
|
+
case "woocommerce_rest_cart_empty": throw errors.CHECKOUT_CART_EMPTY({ message: response.error.message });
|
|
1283
|
+
case "woocommerce_rest_cart_item_error": throw errors.CHECKOUT_CART_INVALID({ message: response.error.message });
|
|
1284
|
+
case "woocommerce_rest_product_partially_out_of_stock": throw errors.CHECKOUT_PRODUCT_INSUFFICIENT_STOCK({ message: response.error.message });
|
|
1285
|
+
case "woocommerce_rest_product_not_purchasable": throw errors.CHECKOUT_PRODUCT_NOT_PURCHASABLE({ message: response.error.message });
|
|
1286
|
+
case "woocommerce_rest_product_out_of_stock": throw errors.CHECKOUT_PRODUCT_OUT_OF_STOCK({ message: response.error.message });
|
|
1287
|
+
default:
|
|
1288
|
+
context.logger.error("Update checkout unhandled error", response.error, { code: response.error.code });
|
|
1289
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
1290
|
+
}
|
|
1291
|
+
return deserializeCheckout(response.data);
|
|
1292
|
+
}),
|
|
1293
|
+
confirm: createProcedure({
|
|
1294
|
+
scope: "api",
|
|
1295
|
+
method: "POST",
|
|
1296
|
+
path: "/checkout",
|
|
1297
|
+
body: ConfirmCheckoutInput,
|
|
1298
|
+
output: Checkout,
|
|
1299
|
+
errors: CONFIRM_CHECKOUT_ERROR_MAP,
|
|
1300
|
+
middlewares: [sessionMiddleware()]
|
|
1301
|
+
}, async ({ context, input, errors }) => {
|
|
1302
|
+
const checkoutResponse = await context.service.wordpress.get("/checkout", {
|
|
1303
|
+
base: WC_STORE_BASE,
|
|
1304
|
+
headers: context.sessionHeaders
|
|
1305
|
+
});
|
|
1306
|
+
if (checkoutResponse.error) switch (checkoutResponse.error.code) {
|
|
1307
|
+
case "woocommerce_rest_checkout_missing_order": throw errors.CHECKOUT_ORDER_NOT_FOUND({ message: checkoutResponse.error.message });
|
|
1308
|
+
default:
|
|
1309
|
+
context.logger.error("Get checkout for confirm unhandled error", checkoutResponse.error, { code: checkoutResponse.error.code });
|
|
1310
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
1311
|
+
}
|
|
1312
|
+
const confirmResponse = await context.service.wordpress.post("/checkout", {
|
|
1313
|
+
base: WC_STORE_BASE,
|
|
1314
|
+
body: {
|
|
1315
|
+
payment_data: input.body.paymentData,
|
|
1316
|
+
customer_password: input.body.customerPassword,
|
|
1317
|
+
customer_note: checkoutResponse.data.customer_note,
|
|
1318
|
+
payment_method: checkoutResponse.data.payment_method,
|
|
1319
|
+
create_account: !!input.body.customerPassword?.length,
|
|
1320
|
+
billing_address: checkoutResponse.data.billing_address,
|
|
1321
|
+
shipping_address: checkoutResponse.data.shipping_address,
|
|
1322
|
+
additional_fields: checkoutResponse.data.additional_fields
|
|
1323
|
+
},
|
|
1324
|
+
headers: context.sessionHeaders
|
|
1325
|
+
});
|
|
1326
|
+
if (confirmResponse.error) switch (confirmResponse.error.code) {
|
|
1327
|
+
case "woocommerce_rest_invalid_address": throw errors.CHECKOUT_ADDRESS_INVALID({ message: confirmResponse.error.message });
|
|
1328
|
+
case "woocommerce_rest_invalid_address_country": throw errors.CHECKOUT_ADDRESS_COUNTRY_INVALID({ message: confirmResponse.error.message });
|
|
1329
|
+
case "woocommerce_rest_cart_coupon_error": throw errors.CHECKOUT_COUPON_INVALID({ message: confirmResponse.error.message });
|
|
1330
|
+
case "woocommerce_rest_invalid_email_address": throw errors.CHECKOUT_EMAIL_INVALID({ message: confirmResponse.error.message });
|
|
1331
|
+
case "woocommerce_rest_missing_email_address": throw errors.CHECKOUT_EMAIL_MISSING({ message: confirmResponse.error.message });
|
|
1332
|
+
case "woocommerce_rest_checkout_process_payment_error": throw errors.CHECKOUT_PAYMENT_FAILED({ message: confirmResponse.error.message });
|
|
1333
|
+
case "woocommerce_rest_checkout_payment_method_disabled": throw errors.CHECKOUT_PAYMENT_METHOD_DISABLED({ message: confirmResponse.error.message });
|
|
1334
|
+
case "woocommerce_rest_checkout_missing_payment_method": throw errors.CHECKOUT_PAYMENT_METHOD_MISSING({ message: confirmResponse.error.message });
|
|
1335
|
+
case "woocommerce_rest_checkout_custom_validation_error": throw errors.CHECKOUT_VALIDATION_FAILED({ message: confirmResponse.error.message });
|
|
1336
|
+
case "woocommerce_rest_guest_checkout_disabled": throw errors.CHECKOUT_GUEST_DISABLED({ message: confirmResponse.error.message });
|
|
1337
|
+
case "woocommerce_rest_checkout_missing_order": throw errors.CHECKOUT_ORDER_NOT_FOUND({ message: confirmResponse.error.message });
|
|
1338
|
+
case "woocommerce_rest_cart_empty": throw errors.CHECKOUT_CART_EMPTY({ message: confirmResponse.error.message });
|
|
1339
|
+
case "woocommerce_rest_cart_item_error": throw errors.CHECKOUT_CART_INVALID({ message: confirmResponse.error.message });
|
|
1340
|
+
case "removed_coupons": throw errors.CHECKOUT_COUPONS_REMOVED({ message: confirmResponse.error.message });
|
|
1341
|
+
case "woocommerce_rest_coupon_reserve_failed": throw errors.CHECKOUT_COUPON_RESERVATION_FAILED({ message: confirmResponse.error.message });
|
|
1342
|
+
case "woocommerce_rest_product_partially_out_of_stock": throw errors.CHECKOUT_PRODUCT_INSUFFICIENT_STOCK({ message: confirmResponse.error.message });
|
|
1343
|
+
case "woocommerce_rest_product_not_purchasable": throw errors.CHECKOUT_PRODUCT_NOT_PURCHASABLE({ message: confirmResponse.error.message });
|
|
1344
|
+
case "woocommerce_rest_product_out_of_stock": throw errors.CHECKOUT_PRODUCT_OUT_OF_STOCK({ message: confirmResponse.error.message });
|
|
1345
|
+
default:
|
|
1346
|
+
context.logger.error("Confirm checkout unhandled error", confirmResponse.error, { code: confirmResponse.error.code });
|
|
1347
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
1348
|
+
}
|
|
1349
|
+
return deserializeCheckout(confirmResponse.data);
|
|
1350
|
+
}),
|
|
1351
|
+
retry: createProcedure({
|
|
1352
|
+
scope: "api",
|
|
1353
|
+
method: "POST",
|
|
1354
|
+
path: "/checkout/{orderId}",
|
|
1355
|
+
params: RetryCheckoutInput.pick({ orderId: true }),
|
|
1356
|
+
body: RetryCheckoutInput.omit({ orderId: true }),
|
|
1357
|
+
output: Checkout,
|
|
1358
|
+
errors: RETRY_CHECKOUT_ERROR_MAP,
|
|
1359
|
+
middlewares: [sessionMiddleware()]
|
|
1360
|
+
}, async ({ context, input, errors }) => {
|
|
1361
|
+
const response = await context.service.wordpress.post(`/checkout/${input.params.orderId}`, {
|
|
1362
|
+
base: WC_STORE_BASE,
|
|
1363
|
+
body: {
|
|
1364
|
+
key: input.body.key,
|
|
1365
|
+
id: input.params.orderId,
|
|
1366
|
+
payment_data: input.body.paymentData,
|
|
1367
|
+
billing_email: input.body.billingEmail,
|
|
1368
|
+
payment_method: input.body.paymentMethod,
|
|
1369
|
+
billing_address: input.body.billingAddress ?? {},
|
|
1370
|
+
shipping_address: input.body.shippingAddress ?? {}
|
|
1371
|
+
},
|
|
1372
|
+
headers: context.sessionHeaders
|
|
1373
|
+
});
|
|
1374
|
+
if (response.error) switch (response.error.code) {
|
|
1375
|
+
case "woocommerce_rest_invalid_billing_email": throw errors.CHECKOUT_EMAIL_INVALID({ message: response.error.message });
|
|
1376
|
+
case "woocommerce_rest_checkout_process_payment_error": throw errors.CHECKOUT_PAYMENT_FAILED({ message: response.error.message });
|
|
1377
|
+
case "woocommerce_rest_checkout_payment_method_disabled": throw errors.CHECKOUT_PAYMENT_METHOD_DISABLED({ message: response.error.message });
|
|
1378
|
+
case "woocommerce_rest_checkout_missing_payment_method": throw errors.CHECKOUT_PAYMENT_METHOD_MISSING({ message: response.error.message });
|
|
1379
|
+
case "woocommerce_rest_invalid_user": throw errors.CHECKOUT_ORDER_FORBIDDEN({ message: response.error.message });
|
|
1380
|
+
case "woocommerce_rest_invalid_order": throw errors.CHECKOUT_ORDER_NOT_FOUND({ message: response.error.message });
|
|
1381
|
+
case "invalid_order_update_status": throw errors.CHECKOUT_ORDER_STATUS_INVALID({ message: response.error.message });
|
|
1382
|
+
default:
|
|
1383
|
+
context.logger.error("Retry checkout unhandled error", response.error, {
|
|
1384
|
+
orderId: input.params.orderId,
|
|
1385
|
+
code: response.error.code
|
|
1386
|
+
});
|
|
1387
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
1388
|
+
}
|
|
1389
|
+
return deserializeCheckout(response.data);
|
|
1390
|
+
})
|
|
1391
|
+
};
|
|
1392
|
+
|
|
1393
|
+
//#endregion
|
|
1394
|
+
//#region src/customer/schema.ts
|
|
1395
|
+
const Customer = z$2.object({
|
|
1396
|
+
id: z$2.number(),
|
|
1397
|
+
email: z$2.string(),
|
|
1398
|
+
firstName: z$2.string(),
|
|
1399
|
+
lastName: z$2.string(),
|
|
1400
|
+
role: z$2.string(),
|
|
1401
|
+
username: z$2.string(),
|
|
1402
|
+
billing: BillingAddress,
|
|
1403
|
+
shipping: ShippingAddress,
|
|
1404
|
+
isPayingCustomer: z$2.boolean(),
|
|
1405
|
+
avatarUrl: z$2.string().nullable(),
|
|
1406
|
+
registeredAt: z$2.number(),
|
|
1407
|
+
meta: Metadata
|
|
1408
|
+
});
|
|
1409
|
+
|
|
1410
|
+
//#endregion
|
|
1411
|
+
//#region src/customer/utils.ts
|
|
1412
|
+
function deserializeCustomer(data) {
|
|
1413
|
+
return {
|
|
1414
|
+
id: data.id,
|
|
1415
|
+
avatarUrl: data.avatar_url.length ? data.avatar_url : null,
|
|
1416
|
+
billing: {
|
|
1417
|
+
firstName: data.billing.first_name,
|
|
1418
|
+
lastName: data.billing.last_name,
|
|
1419
|
+
address1: data.billing.address_1,
|
|
1420
|
+
city: data.billing.city,
|
|
1421
|
+
country: data.billing.country,
|
|
1422
|
+
email: data.billing.email,
|
|
1423
|
+
phone: data.billing.phone,
|
|
1424
|
+
postcode: data.billing.postcode,
|
|
1425
|
+
state: data.billing.state,
|
|
1426
|
+
address2: data.billing.address_2,
|
|
1427
|
+
company: data.billing.company
|
|
1428
|
+
},
|
|
1429
|
+
shipping: {
|
|
1430
|
+
firstName: data.shipping.first_name,
|
|
1431
|
+
lastName: data.shipping.last_name,
|
|
1432
|
+
address1: data.shipping.address_1,
|
|
1433
|
+
city: data.shipping.city,
|
|
1434
|
+
country: data.shipping.country,
|
|
1435
|
+
phone: data.shipping.phone,
|
|
1436
|
+
postcode: data.shipping.postcode,
|
|
1437
|
+
state: data.shipping.state,
|
|
1438
|
+
address2: data.shipping.address_2,
|
|
1439
|
+
company: data.shipping.company
|
|
1440
|
+
},
|
|
1441
|
+
email: data.email,
|
|
1442
|
+
firstName: data.first_name,
|
|
1443
|
+
lastName: data.last_name,
|
|
1444
|
+
isPayingCustomer: data.is_paying_customer,
|
|
1445
|
+
meta: toPublicMetadata(data.meta_data),
|
|
1446
|
+
registeredAt: new Date(data.date_created).getTime(),
|
|
1447
|
+
role: data.role,
|
|
1448
|
+
username: data.username
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
//#endregion
|
|
1453
|
+
//#region src/customer/index.ts
|
|
1454
|
+
const CUSTOMER_ROUTER = { get: createProcedure({
|
|
1455
|
+
scope: "api",
|
|
1456
|
+
method: "GET",
|
|
1457
|
+
path: "/customers",
|
|
1458
|
+
output: Customer
|
|
1459
|
+
}, async ({ context, errors }) => {
|
|
1460
|
+
const auth = await context.getAuthUser();
|
|
1461
|
+
if (!auth) throw errors.FORBIDDEN();
|
|
1462
|
+
const response = await context.service.wordpress.get(`/customers/${auth.id}`, { base: WC_CORE_BASE });
|
|
1463
|
+
if (response.error) throw response.error;
|
|
1464
|
+
return deserializeCustomer(response.data);
|
|
1465
|
+
}) };
|
|
1466
|
+
|
|
1467
|
+
//#endregion
|
|
1468
|
+
//#region src/product/error.ts
|
|
1469
|
+
const GET_PRODUCT_ERROR_MAP = defineErrorMap({ PRODUCT_NOT_FOUND: {
|
|
1470
|
+
status: 404,
|
|
1471
|
+
message: "Product not found."
|
|
1472
|
+
} });
|
|
1473
|
+
const LIST_PRODUCT_ERROR_MAP = defineErrorMap({});
|
|
1474
|
+
const FILTER_PRODUCT_ERROR_MAP = defineErrorMap({});
|
|
1475
|
+
|
|
1476
|
+
//#endregion
|
|
1477
|
+
//#region src/product/utils.ts
|
|
1478
|
+
function deserializeProduct(data) {
|
|
1479
|
+
return {
|
|
1480
|
+
id: data.id,
|
|
1481
|
+
type: data.type,
|
|
1482
|
+
slug: data.slug,
|
|
1483
|
+
name: data.name,
|
|
1484
|
+
sku: data.sku,
|
|
1485
|
+
description: data.description,
|
|
1486
|
+
shortDescription: data.short_description,
|
|
1487
|
+
prices: {
|
|
1488
|
+
price: +data.kizlo.prices.price,
|
|
1489
|
+
salePrice: +data.kizlo.prices.sale_price,
|
|
1490
|
+
regularPrice: +data.kizlo.prices.regular_price
|
|
1491
|
+
},
|
|
1492
|
+
isSoldIndividually: data.sold_individually,
|
|
1493
|
+
onSaleFrom: data.date_on_sale_from ? toTimestamp(data.date_on_sale_from) : null,
|
|
1494
|
+
lowStockRemaining: "data.low_stock_amount",
|
|
1495
|
+
onSaleTo: data.date_on_sale_to ? toTimestamp(data.date_on_sale_to) : null,
|
|
1496
|
+
isInStock: data.stock_status === "instock",
|
|
1497
|
+
stock: data.stock_quantity,
|
|
1498
|
+
images: data.images.map((item) => ({
|
|
1499
|
+
id: item.id,
|
|
1500
|
+
src: item.src,
|
|
1501
|
+
name: item.name,
|
|
1502
|
+
alt: item.alt
|
|
1503
|
+
})),
|
|
1504
|
+
categories: data.categories.map((category) => ({
|
|
1505
|
+
id: category.id,
|
|
1506
|
+
name: category.name,
|
|
1507
|
+
slug: category.slug
|
|
1508
|
+
})),
|
|
1509
|
+
tags: data.tags.map((tag) => ({
|
|
1510
|
+
id: tag.id,
|
|
1511
|
+
name: tag.name,
|
|
1512
|
+
slug: tag.slug
|
|
1513
|
+
})),
|
|
1514
|
+
averageRating: data.average_rating,
|
|
1515
|
+
reviewCount: data.rating_count,
|
|
1516
|
+
attributes: data.kizlo.attributes.map((item) => ({
|
|
1517
|
+
id: item.id,
|
|
1518
|
+
hasVariations: item.has_variations,
|
|
1519
|
+
name: item.name,
|
|
1520
|
+
taxonomy: item.taxonomy,
|
|
1521
|
+
terms: item.terms
|
|
1522
|
+
})),
|
|
1523
|
+
groupedProducts: data.grouped_products,
|
|
1524
|
+
isOnBackorder: data.backordered,
|
|
1525
|
+
isPurchasable: data.purchasable,
|
|
1526
|
+
isOnSale: data.on_sale,
|
|
1527
|
+
parentId: data.parent_id,
|
|
1528
|
+
brands: data.brands,
|
|
1529
|
+
variations: data.kizlo.variations,
|
|
1530
|
+
hasOptions: !!data.kizlo.variations.length,
|
|
1531
|
+
currencyFormat: deserializeCurrencyFormat(data.kizlo.currency_format),
|
|
1532
|
+
meta: toPublicMetadata(data.meta_data),
|
|
1533
|
+
seo: null
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
function deserializeStoreProduct(data) {
|
|
1537
|
+
return {
|
|
1538
|
+
id: data.id,
|
|
1539
|
+
type: data.type,
|
|
1540
|
+
name: data.name,
|
|
1541
|
+
slug: data.slug,
|
|
1542
|
+
sku: data.sku,
|
|
1543
|
+
description: data.description,
|
|
1544
|
+
shortDescription: data.short_description,
|
|
1545
|
+
isInStock: data.is_in_stock,
|
|
1546
|
+
reviewCount: data.review_count,
|
|
1547
|
+
averageRating: data.average_rating,
|
|
1548
|
+
lowStockRemaining: data.low_stock_remaining,
|
|
1549
|
+
isSoldIndividually: data.sold_individually,
|
|
1550
|
+
prices: {
|
|
1551
|
+
price: +data.prices.price,
|
|
1552
|
+
salePrice: +data.prices.sale_price,
|
|
1553
|
+
regularPrice: +data.prices.regular_price
|
|
1554
|
+
},
|
|
1555
|
+
images: data.images.map((item) => ({
|
|
1556
|
+
id: item.id,
|
|
1557
|
+
src: item.src,
|
|
1558
|
+
name: item.name,
|
|
1559
|
+
alt: item.alt
|
|
1560
|
+
})),
|
|
1561
|
+
categories: data.categories.map((category) => ({
|
|
1562
|
+
id: category.id,
|
|
1563
|
+
name: category.name,
|
|
1564
|
+
slug: category.slug
|
|
1565
|
+
})),
|
|
1566
|
+
tags: data.tags.map((tag) => ({
|
|
1567
|
+
id: tag.id,
|
|
1568
|
+
name: tag.name,
|
|
1569
|
+
slug: tag.slug
|
|
1570
|
+
})),
|
|
1571
|
+
attributes: data.attributes.map((item) => ({
|
|
1572
|
+
id: item.id,
|
|
1573
|
+
name: item.name,
|
|
1574
|
+
terms: item.terms,
|
|
1575
|
+
taxonomy: item.taxonomy,
|
|
1576
|
+
hasVariations: item.has_variations
|
|
1577
|
+
})),
|
|
1578
|
+
currencyFormat: deserializeCurrencyFormat(data.prices),
|
|
1579
|
+
brands: data.brands,
|
|
1580
|
+
groupedProducts: data.grouped_products,
|
|
1581
|
+
hasOptions: data.has_options,
|
|
1582
|
+
isOnBackorder: data.is_on_backorder,
|
|
1583
|
+
isPurchasable: data.is_purchasable,
|
|
1584
|
+
isOnSale: data.on_sale,
|
|
1585
|
+
parentId: data.parent,
|
|
1586
|
+
variations: data.variations,
|
|
1587
|
+
stock: data.extensions.kizlo.stock,
|
|
1588
|
+
onSaleFrom: data.extensions.kizlo.on_sale_from ? toTimestamp(data.extensions.kizlo.on_sale_from) : null,
|
|
1589
|
+
onSaleTo: data.extensions.kizlo.on_sale_to ? toTimestamp(data.extensions.kizlo.on_sale_to) : null,
|
|
1590
|
+
seo: null,
|
|
1591
|
+
meta: {}
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
function deserializeProductFilters(data) {
|
|
1595
|
+
if (!data.price_range) return null;
|
|
1596
|
+
const maxPrice = +data.price_range.max_price;
|
|
1597
|
+
const minPrice = +data.price_range.min_price;
|
|
1598
|
+
return {
|
|
1599
|
+
stockStatuses: data.stock_status_counts ?? [],
|
|
1600
|
+
taxonomyTerms: data.kizlo.taxonomy_counts.map((item) => ({
|
|
1601
|
+
id: item.id,
|
|
1602
|
+
name: item.name,
|
|
1603
|
+
count: item.count,
|
|
1604
|
+
description: item.description,
|
|
1605
|
+
parentId: item.parent,
|
|
1606
|
+
slug: item.slug,
|
|
1607
|
+
taxonomy: item.taxonomy,
|
|
1608
|
+
image: item.thumbnail ? {
|
|
1609
|
+
id: 0,
|
|
1610
|
+
alt: item.name,
|
|
1611
|
+
name: item.name,
|
|
1612
|
+
src: item.thumbnail
|
|
1613
|
+
} : null
|
|
1614
|
+
})),
|
|
1615
|
+
attributeTerms: data.kizlo.attribute_counts.map((item) => ({
|
|
1616
|
+
id: item.id,
|
|
1617
|
+
name: item.name,
|
|
1618
|
+
count: item.count,
|
|
1619
|
+
description: item.description,
|
|
1620
|
+
parentId: item.parent,
|
|
1621
|
+
slug: item.slug,
|
|
1622
|
+
swatch: item.swatch,
|
|
1623
|
+
type: item.swatch_type,
|
|
1624
|
+
taxonomy: item.taxonomy
|
|
1625
|
+
})),
|
|
1626
|
+
priceRange: {
|
|
1627
|
+
maxPrice,
|
|
1628
|
+
minPrice
|
|
1629
|
+
},
|
|
1630
|
+
currencyFormat: deserializeCurrencyFormat(data.price_range)
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
function serializeProductListInput(data) {
|
|
1634
|
+
return {
|
|
1635
|
+
after: data?.after,
|
|
1636
|
+
attribute_relation: data?.attributeRelation,
|
|
1637
|
+
before: data?.before,
|
|
1638
|
+
brand: data?.brand,
|
|
1639
|
+
brand_operator: data?.brandOperator,
|
|
1640
|
+
catalog_visibility: data?.catalogVisibility,
|
|
1641
|
+
category: data?.category,
|
|
1642
|
+
category_operator: data?.categoryOperator,
|
|
1643
|
+
featured: data?.featured,
|
|
1644
|
+
max_price: data?.maxPrice ? String(data?.maxPrice) : void 0,
|
|
1645
|
+
min_price: data?.minPrice ? String(data?.minPrice) : void 0,
|
|
1646
|
+
on_sale: data?.onSale,
|
|
1647
|
+
orderby: data?.orderby,
|
|
1648
|
+
parent: normalizeArrayableValue(data?.parent),
|
|
1649
|
+
parent_exclude: normalizeArrayableValue(data?.parentExclude),
|
|
1650
|
+
rating: normalizeArrayableValue(data?.rating)?.map(Number),
|
|
1651
|
+
sku: data?.sku,
|
|
1652
|
+
slug: data?.slug,
|
|
1653
|
+
stock_status: normalizeArrayableValue(data?.stockStatus),
|
|
1654
|
+
tag: data?.tag,
|
|
1655
|
+
tag_operator: data?.tagOperator,
|
|
1656
|
+
type: data?.type,
|
|
1657
|
+
attributes: data?.attributes?.map((item) => ({
|
|
1658
|
+
operator: item.operator,
|
|
1659
|
+
attribute: item.attribute,
|
|
1660
|
+
slug: normalizeArrayableValue(item.slug),
|
|
1661
|
+
term_id: normalizeArrayableValue(item.termId)
|
|
1662
|
+
})),
|
|
1663
|
+
exclude: normalizeArrayableValue(data?.exclude),
|
|
1664
|
+
include: normalizeArrayableValue(data?.include),
|
|
1665
|
+
offset: data?.offset,
|
|
1666
|
+
order: data?.order,
|
|
1667
|
+
page: data?.page,
|
|
1668
|
+
per_page: data?.perPage,
|
|
1669
|
+
related: data?.related,
|
|
1670
|
+
search: data?.search
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
function toTimestamp(date) {
|
|
1674
|
+
return new Date(date).getTime();
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
//#endregion
|
|
1678
|
+
//#region src/product/index.ts
|
|
1679
|
+
const PRODUCT_ROUTER = {
|
|
1680
|
+
get: createProcedure({
|
|
1681
|
+
scope: "api",
|
|
1682
|
+
method: "GET",
|
|
1683
|
+
path: "/products/{identifier}",
|
|
1684
|
+
params: RetrieveProductInput.pick({ identifier: true }),
|
|
1685
|
+
query: RetrieveProductInput.pick({ previewToken: true }).optional(),
|
|
1686
|
+
output: Product,
|
|
1687
|
+
errors: GET_PRODUCT_ERROR_MAP
|
|
1688
|
+
}, async ({ context, input, errors }) => {
|
|
1689
|
+
if (input.query?.previewToken) {
|
|
1690
|
+
const result = await context.verifyPreviewToken(input.query.previewToken);
|
|
1691
|
+
if (!result) throw errors.PRODUCT_NOT_FOUND();
|
|
1692
|
+
const response$1 = await context.service.wordpress.get(`/products/${result.id}`, { base: WC_CORE_BASE });
|
|
1693
|
+
if (response$1.error) switch (response$1.error.code) {
|
|
1694
|
+
case "woocommerce_rest_product_invalid_id": throw errors.PRODUCT_NOT_FOUND({ message: response$1.error.message });
|
|
1695
|
+
default:
|
|
1696
|
+
context.logger.error("Get product preview unhandled error", response$1.error, {
|
|
1697
|
+
id: result.id,
|
|
1698
|
+
code: response$1.error.code
|
|
1699
|
+
});
|
|
1700
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
1701
|
+
}
|
|
1702
|
+
return deserializeProduct(response$1.data);
|
|
1703
|
+
}
|
|
1704
|
+
const response = await context.service.wordpress.get("/products", {
|
|
1705
|
+
searchParams: { slug: input.params.identifier },
|
|
1706
|
+
base: WC_CORE_BASE
|
|
1707
|
+
});
|
|
1708
|
+
if (response.error) switch (response.error.code) {
|
|
1709
|
+
default:
|
|
1710
|
+
context.logger.error("Get product unhandled error", response.error, {
|
|
1711
|
+
identifier: input.params.identifier,
|
|
1712
|
+
code: response.error.code
|
|
1713
|
+
});
|
|
1714
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
1715
|
+
}
|
|
1716
|
+
const data = response.data[0];
|
|
1717
|
+
if (!data) throw errors.PRODUCT_NOT_FOUND();
|
|
1718
|
+
return deserializeProduct(data);
|
|
1719
|
+
}),
|
|
1720
|
+
list: createProcedure({
|
|
1721
|
+
scope: "api",
|
|
1722
|
+
method: "GET",
|
|
1723
|
+
path: "/products",
|
|
1724
|
+
query: ListProductInput.optional(),
|
|
1725
|
+
output: ProductList,
|
|
1726
|
+
errors: LIST_PRODUCT_ERROR_MAP
|
|
1727
|
+
}, async ({ context, input, errors }) => {
|
|
1728
|
+
const searchParams = serializeProductListInput(input.query);
|
|
1729
|
+
const response = await context.service.wordpress.get("/products", {
|
|
1730
|
+
base: WC_STORE_BASE,
|
|
1731
|
+
searchParams: { ...searchParams }
|
|
1732
|
+
});
|
|
1733
|
+
if (response.error) switch (response.error.code) {
|
|
1734
|
+
default:
|
|
1735
|
+
context.logger.error("List products unhandled error", response.error, { code: response.error.code });
|
|
1736
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
1737
|
+
}
|
|
1738
|
+
const list = context.service.wordpress.resolveList({
|
|
1739
|
+
data: response.data,
|
|
1740
|
+
headers: response.headers,
|
|
1741
|
+
searchParams: { ...searchParams }
|
|
1742
|
+
});
|
|
1743
|
+
return {
|
|
1744
|
+
items: list.items.map(deserializeStoreProduct),
|
|
1745
|
+
meta: deserializeListMetadata(list.meta)
|
|
1746
|
+
};
|
|
1747
|
+
}),
|
|
1748
|
+
filters: createProcedure({
|
|
1749
|
+
scope: "api",
|
|
1750
|
+
method: "GET",
|
|
1751
|
+
path: "/products/filters",
|
|
1752
|
+
query: RetrieveProductFiltersInput.optional(),
|
|
1753
|
+
output: ProductFilters.nullable()
|
|
1754
|
+
}, async ({ context, errors, input }) => {
|
|
1755
|
+
const searchParams = serializeProductListInput(input.query);
|
|
1756
|
+
const response = await context.service.wordpress.get("/products/collection-data", {
|
|
1757
|
+
base: WC_STORE_BASE,
|
|
1758
|
+
searchParams: {
|
|
1759
|
+
...searchParams,
|
|
1760
|
+
calculate_price_range: true,
|
|
1761
|
+
calculate_rating_counts: input.query?.ratingFilters,
|
|
1762
|
+
calculate_taxonomy_counts: input.query?.taxonomyFilters,
|
|
1763
|
+
calculate_stock_status_counts: input.query?.stockStatusFilters,
|
|
1764
|
+
calculate_attribute_counts: input.query?.attributeFilters?.map((item) => ({
|
|
1765
|
+
taxonomy: item.taxonomy,
|
|
1766
|
+
query_type: item.queryType
|
|
1767
|
+
}))
|
|
1768
|
+
}
|
|
1769
|
+
});
|
|
1770
|
+
if (response.error) switch (response.error.code) {
|
|
1771
|
+
default:
|
|
1772
|
+
context.logger.error("Filter products unhandled error", response.error, { code: response.error.code });
|
|
1773
|
+
throw errors.INTERNAL_SERVER_ERROR();
|
|
1774
|
+
}
|
|
1775
|
+
return deserializeProductFilters(response.data);
|
|
1776
|
+
})
|
|
1777
|
+
};
|
|
1778
|
+
|
|
1779
|
+
//#endregion
|
|
1780
|
+
//#region src/index.ts
|
|
1781
|
+
function woocommerce() {
|
|
1782
|
+
return createExtension({
|
|
1783
|
+
id: "woocommerce",
|
|
1784
|
+
init: () => {
|
|
1785
|
+
return { router: {
|
|
1786
|
+
cart: CART_ROUTER,
|
|
1787
|
+
products: PRODUCT_ROUTER,
|
|
1788
|
+
checkout: CHECKOUT_ROUTER,
|
|
1789
|
+
customers: CUSTOMER_ROUTER
|
|
1790
|
+
} };
|
|
1791
|
+
}
|
|
1792
|
+
});
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
//#endregion
|
|
1796
|
+
export { woocommerce };
|