@reactionary/commercetools 0.6.9 → 0.7.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/capabilities/cart.capability.js +180 -63
- package/capabilities/employee-invitation.capability.js +1 -1
- package/capabilities/product-list.capability.js +179 -103
- package/core/capability-descriptors.js +3 -2
- package/core/client.js +23 -3
- package/factories/cart/cart.factory.js +60 -10
- package/factories/product-list/product-list.factory.js +68 -33
- package/package.json +2 -2
- package/schema/commercetools.schema.js +14 -3
- package/src/capabilities/cart.capability.d.ts +13 -10
- package/src/capabilities/product-list.capability.d.ts +13 -6
- package/src/core/client.d.ts +3 -0
- package/src/factories/cart/cart.factory.d.ts +8 -8
- package/src/factories/product-list/product-list.factory.d.ts +16 -9
- package/src/schema/commercetools.schema.d.ts +213 -0
|
@@ -11,6 +11,7 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
11
11
|
};
|
|
12
12
|
import {
|
|
13
13
|
error,
|
|
14
|
+
ProductListCapability,
|
|
14
15
|
ProductListItemMutationCreateSchema,
|
|
15
16
|
ProductListItemMutationDeleteSchema,
|
|
16
17
|
ProductListItemMutationUpdateSchema,
|
|
@@ -21,7 +22,6 @@ import {
|
|
|
21
22
|
ProductListMutationDeleteSchema,
|
|
22
23
|
ProductListMutationUpdateSchema,
|
|
23
24
|
ProductListPaginatedResultsSchema,
|
|
24
|
-
ProductListCapability,
|
|
25
25
|
ProductListQueryByIdSchema,
|
|
26
26
|
ProductListQuerySchema,
|
|
27
27
|
ProductListSchema,
|
|
@@ -38,15 +38,62 @@ class CommercetoolsProductListCapability extends ProductListCapability {
|
|
|
38
38
|
this.commercetools = commercetools;
|
|
39
39
|
this.factory = factory;
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Creates a new Commercetools client, optionally upgrading it from Anonymous mode to Guest mode.
|
|
43
|
+
* For now, any Query or Mutation will require an upgrade to Guest mode.
|
|
44
|
+
* In the future, maybe we can delay this upgrade until we actually need it.
|
|
45
|
+
*/
|
|
46
|
+
async getClient(companyIdentifier) {
|
|
47
|
+
let client;
|
|
48
|
+
if (companyIdentifier) {
|
|
49
|
+
client = await this.commercetools.getClientForCompany(companyIdentifier);
|
|
50
|
+
} else {
|
|
51
|
+
client = (await this.commercetools.getClient()).withProjectKey({ projectKey: this.config.projectKey }).me();
|
|
52
|
+
}
|
|
53
|
+
return client;
|
|
54
|
+
}
|
|
55
|
+
async isMine(listIdentifier) {
|
|
56
|
+
if (this.context.session.identityContext?.identity.type !== "Registered") {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (this.context.session.identityContext?.identity.id.userId === listIdentifier.user?.userId) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
async getCompanyForList(listIdentifier) {
|
|
65
|
+
if ("version" in listIdentifier && "company" in listIdentifier) {
|
|
66
|
+
return listIdentifier.company;
|
|
67
|
+
}
|
|
68
|
+
const client = await this.getClient();
|
|
69
|
+
try {
|
|
70
|
+
const listResponse = await client.shoppingLists().withId({ ID: listIdentifier.key }).get().execute();
|
|
71
|
+
if (listResponse.body.businessUnit) {
|
|
72
|
+
return {
|
|
73
|
+
taxIdentifier: listResponse.body.businessUnit.key
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return void 0;
|
|
77
|
+
} catch (e) {
|
|
78
|
+
console.error("Error fetching list for company information:", e);
|
|
79
|
+
return void 0;
|
|
80
|
+
}
|
|
44
81
|
}
|
|
45
82
|
async getById(payload) {
|
|
46
83
|
try {
|
|
47
|
-
const
|
|
84
|
+
const companyIdentifier = await this.getCompanyForList(payload.identifier);
|
|
85
|
+
const client = await this.getClient(companyIdentifier);
|
|
48
86
|
const response = await client.shoppingLists().withId({ ID: payload.identifier.key }).get().execute();
|
|
49
|
-
|
|
87
|
+
const payloadResult = this.factory.parseProductList(this.context, response.body);
|
|
88
|
+
if (!await this.isMine(payloadResult.identifier)) {
|
|
89
|
+
if (!payloadResult.published) {
|
|
90
|
+
return error({
|
|
91
|
+
type: "NotFound",
|
|
92
|
+
identifier: payload.identifier
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return success(payloadResult);
|
|
50
97
|
} catch (err) {
|
|
51
98
|
if (err.statusCode === 404) {
|
|
52
99
|
return error({
|
|
@@ -61,65 +108,101 @@ class CommercetoolsProductListCapability extends ProductListCapability {
|
|
|
61
108
|
async queryLists(payload) {
|
|
62
109
|
if (this.context.session.identityContext?.identity?.type !== "Registered") {
|
|
63
110
|
return success(this.factory.parseProductListPaginatedResult(this.context, {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}));
|
|
111
|
+
limit: payload.search.paginationOptions.pageSize,
|
|
112
|
+
offset: (payload.search.paginationOptions.pageNumber - 1) * payload.search.paginationOptions.pageSize,
|
|
113
|
+
count: payload.search.paginationOptions.pageSize,
|
|
114
|
+
results: [],
|
|
115
|
+
total: 0
|
|
116
|
+
}, payload));
|
|
71
117
|
}
|
|
72
|
-
const client = await this.getClient();
|
|
118
|
+
const client = await this.getClient(payload.search.company);
|
|
119
|
+
let where = ``;
|
|
120
|
+
const listTypeFilter = `custom(fields(listType=:listType))`;
|
|
121
|
+
const allOfMineFilter = `(customer(id=:customerId))`;
|
|
122
|
+
const othersFilter = `(customer(id != :customerId) and custom(fields(published=true)))`;
|
|
123
|
+
let companyFilter = `businessUnit is not defined`;
|
|
124
|
+
if (payload.search.company) {
|
|
125
|
+
companyFilter = `businessUnit(key=:companyKey)`;
|
|
126
|
+
}
|
|
127
|
+
where = `((${listTypeFilter}) and (${companyFilter})) and (${allOfMineFilter} or ${othersFilter})`;
|
|
128
|
+
const customerId = this.context.session.identityContext?.identity.type === "Registered" ? this.context.session.identityContext?.identity.id.userId : "anonymous";
|
|
129
|
+
const companyKey = payload.search.company?.taxIdentifier || void 0;
|
|
73
130
|
const response = await client.shoppingLists().get({
|
|
74
131
|
queryArgs: {
|
|
75
|
-
where
|
|
132
|
+
where,
|
|
76
133
|
sort: "createdAt desc",
|
|
77
134
|
"var.listType": payload.search.listType,
|
|
135
|
+
"var.published": true,
|
|
136
|
+
"var.customerId": customerId,
|
|
137
|
+
"var.companyKey": companyKey,
|
|
78
138
|
limit: payload.search.paginationOptions.pageSize,
|
|
79
139
|
offset: (payload.search.paginationOptions.pageNumber - 1) * payload.search.paginationOptions.pageSize
|
|
80
140
|
}
|
|
81
141
|
}).execute();
|
|
82
|
-
return success(this.factory.parseProductListPaginatedResult(this.context,
|
|
83
|
-
items: response.body.results.map((list) => this.parseSingle(list)),
|
|
84
|
-
pageNumber: payload.search.paginationOptions.pageNumber,
|
|
85
|
-
pageSize: payload.search.paginationOptions.pageSize,
|
|
86
|
-
totalCount: response.body.total || 0,
|
|
87
|
-
totalPages: Math.ceil((response.body.total || 0) / payload.search.paginationOptions.pageSize),
|
|
88
|
-
identifier: payload.search
|
|
89
|
-
}));
|
|
142
|
+
return success(this.factory.parseProductListPaginatedResult(this.context, response.body, payload));
|
|
90
143
|
}
|
|
91
|
-
|
|
92
|
-
const client = await this.getClient();
|
|
144
|
+
addListPayload(payload) {
|
|
93
145
|
const localeString = this.getLocaleString();
|
|
146
|
+
let businessUnitReference = void 0;
|
|
147
|
+
let customerReference = void 0;
|
|
148
|
+
if (payload.company) {
|
|
149
|
+
businessUnitReference = {
|
|
150
|
+
typeId: "business-unit",
|
|
151
|
+
key: payload.company.taxIdentifier
|
|
152
|
+
};
|
|
153
|
+
if (this.context.session.identityContext?.identity.type === "Registered" && this.context.session.identityContext?.identity.id) {
|
|
154
|
+
customerReference = {
|
|
155
|
+
typeId: "customer",
|
|
156
|
+
id: this.context.session.identityContext?.identity.id.userId
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const customFields = {
|
|
161
|
+
type: {
|
|
162
|
+
typeId: "type",
|
|
163
|
+
key: "reactionaryShoppingList"
|
|
164
|
+
},
|
|
165
|
+
fields: {
|
|
166
|
+
listType: payload.list.type,
|
|
167
|
+
imageUrl: payload.list.image ? payload.list.image.sourceUrl : void 0,
|
|
168
|
+
publishedDate: payload.list.publishDate ? new Date(payload.list.publishDate) : void 0,
|
|
169
|
+
published: payload.list.published && true
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const draft = {
|
|
173
|
+
name: { [localeString]: payload.list.name },
|
|
174
|
+
businessUnit: businessUnitReference,
|
|
175
|
+
customer: customerReference,
|
|
176
|
+
description: payload.list.description ? { [localeString]: payload.list.description } : void 0,
|
|
177
|
+
custom: customFields
|
|
178
|
+
};
|
|
179
|
+
return draft;
|
|
180
|
+
}
|
|
181
|
+
async addList(mutation) {
|
|
182
|
+
const client = await this.getClient(mutation.company);
|
|
94
183
|
if (this.context.session.identityContext?.identity?.type !== "Registered") {
|
|
95
184
|
return error({
|
|
96
185
|
type: "InvalidInput",
|
|
97
186
|
error: "Only registered users can have product lists"
|
|
98
187
|
});
|
|
99
188
|
}
|
|
100
|
-
const
|
|
101
|
-
name: { [localeString]: mutation.list.name },
|
|
102
|
-
description: mutation.list.description ? { [localeString]: mutation.list.description } : void 0,
|
|
103
|
-
custom: {
|
|
104
|
-
type: {
|
|
105
|
-
key: "reactionaryShoppingList",
|
|
106
|
-
typeId: "type"
|
|
107
|
-
},
|
|
108
|
-
fields: {
|
|
109
|
-
listType: mutation.list.type,
|
|
110
|
-
imageUrl: mutation.list.image ? mutation.list.image.sourceUrl : void 0,
|
|
111
|
-
publishedDate: mutation.list.publishDate ? new Date(mutation.list.publishDate) : void 0,
|
|
112
|
-
published: mutation.list.published || true
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
};
|
|
189
|
+
const list = this.addListPayload(mutation);
|
|
116
190
|
const response = await client.shoppingLists().post({
|
|
117
|
-
body:
|
|
191
|
+
body: list
|
|
118
192
|
}).execute();
|
|
119
|
-
return success(this.factory.parseProductList(this.context,
|
|
193
|
+
return success(this.factory.parseProductList(this.context, response.body));
|
|
120
194
|
}
|
|
121
195
|
async updateList(mutation) {
|
|
122
|
-
const
|
|
196
|
+
const companyIdentifier = await this.getCompanyForList(mutation.list);
|
|
197
|
+
const client = await this.getClient(companyIdentifier);
|
|
198
|
+
if (!await this.isMine(mutation.list)) {
|
|
199
|
+
if (await this.isUnpublished(mutation.list, client)) {
|
|
200
|
+
return error({
|
|
201
|
+
type: "InvalidInput",
|
|
202
|
+
error: "Cannot update a list that is not yours, unless it is published"
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
123
206
|
const actions = [];
|
|
124
207
|
const localeString = this.getLocaleString();
|
|
125
208
|
if (mutation.name) {
|
|
@@ -161,10 +244,19 @@ class CommercetoolsProductListCapability extends ProductListCapability {
|
|
|
161
244
|
actions
|
|
162
245
|
};
|
|
163
246
|
const response = await client.shoppingLists().withId({ ID: mutation.list.key }).post({ body: update }).execute();
|
|
164
|
-
return success(this.factory.parseProductList(this.context,
|
|
247
|
+
return success(this.factory.parseProductList(this.context, response.body));
|
|
165
248
|
}
|
|
166
249
|
async deleteList(mutation) {
|
|
167
|
-
const
|
|
250
|
+
const companyIdentifier = await this.getCompanyForList(mutation.list);
|
|
251
|
+
const client = await this.getClient(companyIdentifier);
|
|
252
|
+
if (!await this.isMine(mutation.list)) {
|
|
253
|
+
if (await this.isUnpublished(mutation.list, client)) {
|
|
254
|
+
return error({
|
|
255
|
+
type: "InvalidInput",
|
|
256
|
+
error: "Cannot delete from a list that is not yours, unless it is published"
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
168
260
|
const newestVersion = await client.shoppingLists().withId({ ID: mutation.list.key }).get().execute().then((response) => response.body.version);
|
|
169
261
|
await client.shoppingLists().withId({ ID: mutation.list.key }).delete({
|
|
170
262
|
queryArgs: {
|
|
@@ -174,22 +266,25 @@ class CommercetoolsProductListCapability extends ProductListCapability {
|
|
|
174
266
|
return success(void 0);
|
|
175
267
|
}
|
|
176
268
|
async queryListItems(query) {
|
|
177
|
-
const
|
|
269
|
+
const companyIdentifier = await this.getCompanyForList(query.search.list);
|
|
270
|
+
const client = await this.getClient(companyIdentifier);
|
|
178
271
|
const response = await client.shoppingLists().withId({ ID: query.search.list.key }).get({
|
|
179
272
|
queryArgs: { expand: "lineItems[*].variant" }
|
|
180
273
|
}).execute();
|
|
181
|
-
|
|
182
|
-
return success(this.factory.parseProductListItemPaginatedResult(this.context, {
|
|
183
|
-
items: items.slice((query.search.paginationOptions.pageNumber - 1) * query.search.paginationOptions.pageSize, query.search.paginationOptions.pageNumber * query.search.paginationOptions.pageSize),
|
|
184
|
-
identifier: query.search,
|
|
185
|
-
pageNumber: query.search.paginationOptions.pageNumber,
|
|
186
|
-
pageSize: query.search.paginationOptions.pageSize,
|
|
187
|
-
totalCount: items.length,
|
|
188
|
-
totalPages: Math.ceil(items.length / query.search.paginationOptions.pageSize)
|
|
189
|
-
}));
|
|
274
|
+
return success(this.factory.parseProductListItemPaginatedResult(this.context, response.body, query));
|
|
190
275
|
}
|
|
191
276
|
async addItem(mutation) {
|
|
192
|
-
const
|
|
277
|
+
const companyIdentifier = await this.getCompanyForList(mutation.list);
|
|
278
|
+
const client = await this.getClient(companyIdentifier);
|
|
279
|
+
const myList = await this.isMine(mutation.list);
|
|
280
|
+
if (!myList) {
|
|
281
|
+
if (await this.isUnpublished(mutation.list, client)) {
|
|
282
|
+
return error({
|
|
283
|
+
type: "InvalidInput",
|
|
284
|
+
error: "Cannot add items to a list that is not yours, unless it is published"
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
193
288
|
const lineItemDraft = {
|
|
194
289
|
action: "addLineItem",
|
|
195
290
|
sku: mutation.listItem.variant.sku,
|
|
@@ -215,10 +310,24 @@ class CommercetoolsProductListCapability extends ProductListCapability {
|
|
|
215
310
|
if (lastItem.variant?.sku !== mutation.listItem.variant.sku) {
|
|
216
311
|
throw new Error("The added line item is not the last item in the list, cannot reliably determine the identifier of the added item");
|
|
217
312
|
}
|
|
218
|
-
return success(this.factory.parseProductListItem(this.context,
|
|
313
|
+
return success(this.factory.parseProductListItem(this.context, { listIdentifier: mutation.list, lineItem: lastItem }));
|
|
314
|
+
}
|
|
315
|
+
async isUnpublished(list, client) {
|
|
316
|
+
const response = await client.shoppingLists().withId({ ID: list.key }).get().execute();
|
|
317
|
+
const isPublished = response.body.custom?.fields["published"] && true;
|
|
318
|
+
return !isPublished;
|
|
219
319
|
}
|
|
220
320
|
async deleteItem(mutation) {
|
|
221
|
-
const
|
|
321
|
+
const companyIdentifier = await this.getCompanyForList(mutation.listItem.list);
|
|
322
|
+
const client = await this.getClient(companyIdentifier);
|
|
323
|
+
if (!await this.isMine(mutation.listItem.list)) {
|
|
324
|
+
if (await this.isUnpublished(mutation.listItem.list, client)) {
|
|
325
|
+
return error({
|
|
326
|
+
type: "InvalidInput",
|
|
327
|
+
error: "Cannot delete items to a list that is not yours, unless it is published"
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
222
331
|
const update = {
|
|
223
332
|
version: 0,
|
|
224
333
|
// The auto-correcting middleware will deal with the version
|
|
@@ -231,7 +340,16 @@ class CommercetoolsProductListCapability extends ProductListCapability {
|
|
|
231
340
|
return success(void 0);
|
|
232
341
|
}
|
|
233
342
|
async updateItem(mutation) {
|
|
234
|
-
const
|
|
343
|
+
const companyIdentifier = await this.getCompanyForList(mutation.listItem.list);
|
|
344
|
+
const client = await this.getClient(companyIdentifier);
|
|
345
|
+
if (!await this.isMine(mutation.listItem.list)) {
|
|
346
|
+
if (await this.isUnpublished(mutation.listItem.list, client)) {
|
|
347
|
+
return error({
|
|
348
|
+
type: "InvalidInput",
|
|
349
|
+
error: "Cannot update items in a list that is not yours, unless it is published"
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
235
353
|
const actions = [];
|
|
236
354
|
if (mutation.quantity !== void 0) {
|
|
237
355
|
actions.push({
|
|
@@ -265,7 +383,7 @@ class CommercetoolsProductListCapability extends ProductListCapability {
|
|
|
265
383
|
if (!updatedLineItem) {
|
|
266
384
|
throw new Error("Failed to find the updated line item in response");
|
|
267
385
|
}
|
|
268
|
-
return success(this.factory.parseProductListItem(this.context,
|
|
386
|
+
return success(this.factory.parseProductListItem(this.context, { listIdentifier: mutation.listItem.list, lineItem: updatedLineItem }));
|
|
269
387
|
}
|
|
270
388
|
/**
|
|
271
389
|
* It is not clear to me, why i'd want my CUSTOMER defined resources to be localized, since that means, if he changes visual language,
|
|
@@ -274,48 +392,6 @@ class CommercetoolsProductListCapability extends ProductListCapability {
|
|
|
274
392
|
getLocaleString() {
|
|
275
393
|
return "en";
|
|
276
394
|
}
|
|
277
|
-
parseSingle(list) {
|
|
278
|
-
const localeString = this.getLocaleString();
|
|
279
|
-
const listType = list.custom?.fields["listType"] || "favorite";
|
|
280
|
-
const image = list.custom?.fields["imageUrl"];
|
|
281
|
-
const published = list.custom?.fields["published"] && true;
|
|
282
|
-
const publishDateDate = list.custom?.fields["publishedDate"];
|
|
283
|
-
let publishedDate;
|
|
284
|
-
if (publishDateDate) {
|
|
285
|
-
publishedDate = new Date(publishDateDate).toISOString();
|
|
286
|
-
}
|
|
287
|
-
return {
|
|
288
|
-
identifier: {
|
|
289
|
-
listType,
|
|
290
|
-
key: list.id
|
|
291
|
-
},
|
|
292
|
-
type: listType,
|
|
293
|
-
name: list.name[localeString] || "Unnamed List",
|
|
294
|
-
description: list.description?.[localeString] || "",
|
|
295
|
-
published,
|
|
296
|
-
publishDate: publishedDate,
|
|
297
|
-
image: {
|
|
298
|
-
sourceUrl: image || "",
|
|
299
|
-
altText: list.name[localeString] || "List Image"
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
parseProductListItem(listIdentifier, lineItem) {
|
|
304
|
-
const localeString = this.getLocaleString();
|
|
305
|
-
return {
|
|
306
|
-
identifier: {
|
|
307
|
-
list: listIdentifier,
|
|
308
|
-
key: lineItem.id
|
|
309
|
-
},
|
|
310
|
-
variant: {
|
|
311
|
-
sku: lineItem.variant?.sku || ""
|
|
312
|
-
},
|
|
313
|
-
quantity: lineItem.quantity,
|
|
314
|
-
notes: lineItem.custom?.fields["notes"] || "",
|
|
315
|
-
order: lineItem.custom?.fields["order"] || 1
|
|
316
|
-
// Commercetools doesn't have explicit ordering
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
395
|
}
|
|
320
396
|
__decorateClass([
|
|
321
397
|
Reactionary({
|
|
@@ -26,7 +26,8 @@ import {
|
|
|
26
26
|
ProfileSchema,
|
|
27
27
|
PriceSchema,
|
|
28
28
|
ShippingMethodSchema,
|
|
29
|
-
StoreSchema
|
|
29
|
+
StoreSchema,
|
|
30
|
+
CartPaginatedSearchResultSchema
|
|
30
31
|
} from "@reactionary/core";
|
|
31
32
|
import {
|
|
32
33
|
} from "../schema/capabilities.schema.js";
|
|
@@ -186,7 +187,7 @@ const capabilityDescriptors = {
|
|
|
186
187
|
cart: {
|
|
187
188
|
isEnabled: (caps) => caps.cart?.enabled,
|
|
188
189
|
getOverride: (caps) => caps.cart,
|
|
189
|
-
createDefaultFactory: () => new CommercetoolsCartFactory(CartSchema, CartIdentifierSchema),
|
|
190
|
+
createDefaultFactory: () => new CommercetoolsCartFactory(CartSchema, CartIdentifierSchema, CartPaginatedSearchResultSchema),
|
|
190
191
|
createDefaultCapability: (args) => new CommercetoolsCartCapability(
|
|
191
192
|
args.config,
|
|
192
193
|
args.cache,
|
package/core/client.js
CHANGED
|
@@ -10,7 +10,9 @@ import {
|
|
|
10
10
|
import * as crypto from "crypto";
|
|
11
11
|
import createDebug from "debug";
|
|
12
12
|
import { RequestContextTokenCache } from "./token-cache.js";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
CommercetoolsSessionSchema
|
|
15
|
+
} from "../schema/session.schema.js";
|
|
14
16
|
const debug = createDebug("reactionary:commercetools");
|
|
15
17
|
const PROVIDER_SESSION_KEY = "COMMERCETOOLS_PROVIDER";
|
|
16
18
|
class CommercetoolsAPI {
|
|
@@ -22,7 +24,10 @@ class CommercetoolsAPI {
|
|
|
22
24
|
constructor(config, context) {
|
|
23
25
|
this.config = config;
|
|
24
26
|
this.context = context;
|
|
25
|
-
this.tokenCache = new RequestContextTokenCache(
|
|
27
|
+
this.tokenCache = new RequestContextTokenCache(
|
|
28
|
+
this.context,
|
|
29
|
+
PROVIDER_SESSION_KEY
|
|
30
|
+
);
|
|
26
31
|
}
|
|
27
32
|
async getClient() {
|
|
28
33
|
if (!this.client) {
|
|
@@ -30,6 +35,17 @@ class CommercetoolsAPI {
|
|
|
30
35
|
}
|
|
31
36
|
return this.client;
|
|
32
37
|
}
|
|
38
|
+
async getClientForCompany(company) {
|
|
39
|
+
if (this.context.session.identityContext.identity.type !== "Registered") {
|
|
40
|
+
throw new Error("Only registered identities can have company clients");
|
|
41
|
+
}
|
|
42
|
+
const companyClient = (await this.getAdminClient()).withProjectKey({ projectKey: this.config.projectKey }).asAssociate().withAssociateIdValue({
|
|
43
|
+
associateId: this.context.session.identityContext.identity.id.userId
|
|
44
|
+
}).inBusinessUnitKeyWithBusinessUnitKeyValue({
|
|
45
|
+
businessUnitKey: company.taxIdentifier
|
|
46
|
+
});
|
|
47
|
+
return companyClient;
|
|
48
|
+
}
|
|
33
49
|
async getAdminClient() {
|
|
34
50
|
if (!this.adminClient) {
|
|
35
51
|
this.adminClient = this.createAdminClient();
|
|
@@ -189,7 +205,11 @@ class CommercetoolsAPI {
|
|
|
189
205
|
});
|
|
190
206
|
}
|
|
191
207
|
async logout() {
|
|
192
|
-
await this.tokenCache.set({
|
|
208
|
+
await this.tokenCache.set({
|
|
209
|
+
token: "",
|
|
210
|
+
refreshToken: "",
|
|
211
|
+
expirationTime: 0
|
|
212
|
+
});
|
|
193
213
|
const identity = {
|
|
194
214
|
type: "Anonymous"
|
|
195
215
|
};
|
|
@@ -4,21 +4,64 @@ import {
|
|
|
4
4
|
class CommercetoolsCartFactory {
|
|
5
5
|
cartSchema;
|
|
6
6
|
cartIdentifierSchema;
|
|
7
|
-
|
|
7
|
+
cartPaginatedSearchResultSchema;
|
|
8
|
+
constructor(cartSchema, cartIdentifierSchema, cartPaginatedSearchResultSchema) {
|
|
8
9
|
this.cartSchema = cartSchema;
|
|
9
10
|
this.cartIdentifierSchema = cartIdentifierSchema;
|
|
11
|
+
this.cartPaginatedSearchResultSchema = cartPaginatedSearchResultSchema;
|
|
12
|
+
}
|
|
13
|
+
parseCartPaginatedSearchResult(_context, data, _query) {
|
|
14
|
+
const result = {
|
|
15
|
+
pageNumber: _query.search.paginationOptions.pageNumber,
|
|
16
|
+
pageSize: _query.search.paginationOptions.pageSize,
|
|
17
|
+
totalCount: data.total || 0,
|
|
18
|
+
totalPages: Math.ceil(
|
|
19
|
+
(data.total || 0) / _query.search.paginationOptions.pageSize
|
|
20
|
+
),
|
|
21
|
+
items: data.results.map(
|
|
22
|
+
(cart) => this.parseCartSearchResultItem(_context, cart)
|
|
23
|
+
),
|
|
24
|
+
identifier: _query.search
|
|
25
|
+
};
|
|
26
|
+
return this.cartPaginatedSearchResultSchema.parse(result);
|
|
10
27
|
}
|
|
11
28
|
parseCartIdentifier(_context, data) {
|
|
12
29
|
return this.cartIdentifierSchema.parse({
|
|
13
|
-
key: data.
|
|
14
|
-
version: data.version || 0
|
|
30
|
+
key: data.id || "",
|
|
31
|
+
version: data.version || 0,
|
|
32
|
+
company: data.businessUnit ? { taxIdentifier: data.businessUnit.key } : void 0
|
|
15
33
|
});
|
|
16
34
|
}
|
|
35
|
+
parseCartSearchResultItem(context, data) {
|
|
36
|
+
const identifier = this.parseCartIdentifier(context, data);
|
|
37
|
+
const numItems = data.lineItems.length;
|
|
38
|
+
const lastModifiedDate = data.lastModifiedAt;
|
|
39
|
+
let company;
|
|
40
|
+
if (data.businessUnit) {
|
|
41
|
+
company = {
|
|
42
|
+
taxIdentifier: data.businessUnit.key
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const result = {
|
|
46
|
+
identifier,
|
|
47
|
+
user: {
|
|
48
|
+
userId: data.customerId || data.anonymousId || "???"
|
|
49
|
+
},
|
|
50
|
+
company,
|
|
51
|
+
name: data.custom?.fields["name"] || "",
|
|
52
|
+
numItems,
|
|
53
|
+
lastModifiedDate
|
|
54
|
+
};
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
17
57
|
parseCart(context, data) {
|
|
18
|
-
const identifier = this.parseCartIdentifier(context,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
58
|
+
const identifier = this.parseCartIdentifier(context, data);
|
|
59
|
+
let company;
|
|
60
|
+
if (data.businessUnit) {
|
|
61
|
+
company = {
|
|
62
|
+
taxIdentifier: data.businessUnit.key
|
|
63
|
+
};
|
|
64
|
+
}
|
|
22
65
|
const items = [];
|
|
23
66
|
for (const lineItem of data.lineItems) {
|
|
24
67
|
items.push(this.parseCartItem(lineItem));
|
|
@@ -73,9 +116,10 @@ class CommercetoolsCartFactory {
|
|
|
73
116
|
}
|
|
74
117
|
const result = {
|
|
75
118
|
identifier,
|
|
76
|
-
|
|
77
|
-
userId: "???"
|
|
119
|
+
user: {
|
|
120
|
+
userId: data.customerId || data.anonymousId || "???"
|
|
78
121
|
},
|
|
122
|
+
company,
|
|
79
123
|
name: data.custom?.fields["name"] || "",
|
|
80
124
|
description: data.custom?.fields["description"] || "",
|
|
81
125
|
price,
|
|
@@ -104,7 +148,13 @@ class CommercetoolsCartFactory {
|
|
|
104
148
|
const currency = lineItem.price.value.currencyCode.toUpperCase();
|
|
105
149
|
return CartItemSchema.parse({
|
|
106
150
|
identifier: {
|
|
107
|
-
key: lineItem.id
|
|
151
|
+
key: lineItem.id,
|
|
152
|
+
...lineItem.priceMode === "ExternalPrice" && {
|
|
153
|
+
originalPrice: {
|
|
154
|
+
value: lineItem.price.value.centAmount / 100,
|
|
155
|
+
currency
|
|
156
|
+
}
|
|
157
|
+
}
|
|
108
158
|
},
|
|
109
159
|
product: {
|
|
110
160
|
key: lineItem.productId
|
|
@@ -11,53 +11,88 @@ class CommercetoolsProductListFactory {
|
|
|
11
11
|
this.productListPaginatedSchema = productListPaginatedSchema;
|
|
12
12
|
this.productListItemPaginatedSchema = productListItemPaginatedSchema;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
parseProductListPaginatedResult(_context, data) {
|
|
21
|
-
return this.productListPaginatedSchema.parse(data);
|
|
22
|
-
}
|
|
23
|
-
parseProductListItemPaginatedResult(_context, data) {
|
|
24
|
-
return this.productListItemPaginatedSchema.parse(data);
|
|
14
|
+
/**
|
|
15
|
+
* This is a customer owned resource, so we just use english as otherwise it will fail if he changes the visual language settings.
|
|
16
|
+
* @returns
|
|
17
|
+
*/
|
|
18
|
+
getLocaleString() {
|
|
19
|
+
return "en";
|
|
25
20
|
}
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
21
|
+
parseProductList(_context, data) {
|
|
22
|
+
const localeString = this.getLocaleString();
|
|
23
|
+
const listType = data.custom?.fields["listType"] || "favorite";
|
|
24
|
+
const image = data.custom?.fields["imageUrl"];
|
|
25
|
+
const published = data.custom?.fields["published"] && true;
|
|
26
|
+
const publishDateDate = data.custom?.fields["publishedDate"];
|
|
27
|
+
let publishedDate;
|
|
28
|
+
if (publishDateDate) {
|
|
29
|
+
publishedDate = new Date(publishDateDate).toISOString();
|
|
30
|
+
}
|
|
31
|
+
const result = {
|
|
33
32
|
identifier: {
|
|
34
33
|
listType,
|
|
35
|
-
key:
|
|
34
|
+
key: data.id,
|
|
35
|
+
user: data.customer ? {
|
|
36
|
+
userId: data.customer.id
|
|
37
|
+
} : void 0,
|
|
38
|
+
version: Number(data.version),
|
|
39
|
+
company: data.businessUnit ? { taxIdentifier: data.businessUnit.key } : void 0
|
|
36
40
|
},
|
|
37
41
|
type: listType,
|
|
38
|
-
name:
|
|
39
|
-
description:
|
|
42
|
+
name: data.name[localeString] || "Unnamed List",
|
|
43
|
+
description: data.description?.[localeString] || "",
|
|
40
44
|
published,
|
|
41
|
-
publishDate,
|
|
45
|
+
publishDate: publishedDate,
|
|
42
46
|
image: {
|
|
43
47
|
sourceUrl: image || "",
|
|
44
|
-
altText:
|
|
48
|
+
altText: data.name[localeString] || "List Image"
|
|
45
49
|
}
|
|
46
|
-
}
|
|
50
|
+
};
|
|
51
|
+
return this.productListSchema.parse(result);
|
|
47
52
|
}
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
parseProductListItem(_context, data) {
|
|
54
|
+
const localeString = this.getLocaleString();
|
|
55
|
+
const result = {
|
|
50
56
|
identifier: {
|
|
51
|
-
list: listIdentifier,
|
|
52
|
-
key: lineItem.id
|
|
57
|
+
list: data.listIdentifier,
|
|
58
|
+
key: data.lineItem.id
|
|
53
59
|
},
|
|
54
60
|
variant: {
|
|
55
|
-
sku: lineItem.variant?.sku || ""
|
|
61
|
+
sku: data.lineItem.variant?.sku || ""
|
|
56
62
|
},
|
|
57
|
-
quantity: lineItem.quantity,
|
|
58
|
-
notes: lineItem.custom?.fields["notes"] || "",
|
|
59
|
-
order: lineItem.custom?.fields["order"] || 1
|
|
60
|
-
|
|
63
|
+
quantity: data.lineItem.quantity,
|
|
64
|
+
notes: data.lineItem.custom?.fields["notes"] || "",
|
|
65
|
+
order: data.lineItem.custom?.fields["order"] || 1
|
|
66
|
+
// Commercetools doesn't have explicit ordering
|
|
67
|
+
};
|
|
68
|
+
return this.productListItemSchema.parse(result);
|
|
69
|
+
}
|
|
70
|
+
parseProductListPaginatedResult(context, data, query) {
|
|
71
|
+
const result = {
|
|
72
|
+
items: (data.results || []).map((list) => this.parseProductList(context, list)),
|
|
73
|
+
pageNumber: query.search.paginationOptions.pageNumber,
|
|
74
|
+
pageSize: query.search.paginationOptions.pageSize,
|
|
75
|
+
totalCount: data.total || 0,
|
|
76
|
+
totalPages: Math.ceil((data.total || 0) / query.search.paginationOptions.pageSize),
|
|
77
|
+
identifier: query.search
|
|
78
|
+
};
|
|
79
|
+
return this.productListPaginatedSchema.parse(result);
|
|
80
|
+
}
|
|
81
|
+
parseProductListItemPaginatedResult(context, data, query) {
|
|
82
|
+
const originalItemCount = data.lineItems.length;
|
|
83
|
+
const items = (data.lineItems || []).slice((query.search.paginationOptions.pageNumber - 1) * query.search.paginationOptions.pageSize, query.search.paginationOptions.pageNumber * query.search.paginationOptions.pageSize);
|
|
84
|
+
const result = {
|
|
85
|
+
items: items.map((x) => this.parseProductListItem(context, {
|
|
86
|
+
listIdentifier: query.search.list,
|
|
87
|
+
lineItem: x
|
|
88
|
+
})),
|
|
89
|
+
identifier: query.search,
|
|
90
|
+
pageNumber: query.search.paginationOptions.pageNumber,
|
|
91
|
+
pageSize: query.search.paginationOptions.pageSize,
|
|
92
|
+
totalCount: originalItemCount,
|
|
93
|
+
totalPages: Math.ceil(originalItemCount / query.search.paginationOptions.pageSize)
|
|
94
|
+
};
|
|
95
|
+
return this.productListItemPaginatedSchema.parse(result);
|
|
61
96
|
}
|
|
62
97
|
}
|
|
63
98
|
export {
|