@reactionary/magento 0.0.1 → 0.10.19

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.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/capabilities/cart.capability.js +22 -22
  3. package/capabilities/category.capability.js +10 -9
  4. package/capabilities/checkout.capability.js +308 -0
  5. package/capabilities/identity.capability.js +31 -16
  6. package/capabilities/inventory.capability.js +2 -2
  7. package/capabilities/order-search.capability.js +150 -0
  8. package/capabilities/order.capability.js +51 -0
  9. package/capabilities/price.capability.js +2 -2
  10. package/capabilities/product-associations.capability.js +118 -0
  11. package/capabilities/product-recommendations.capability.js +148 -0
  12. package/capabilities/product-reviews.capability.js +182 -0
  13. package/capabilities/product-search.capability.js +2 -2
  14. package/capabilities/product.capability.js +6 -5
  15. package/capabilities/profile.capability.js +283 -0
  16. package/core/client.js +324 -24
  17. package/core/initialize.js +150 -2
  18. package/core/product-reviews.graphql.js +72 -0
  19. package/factories/category/category.factory.js +1 -1
  20. package/factories/checkout/checkout.factory.js +203 -0
  21. package/factories/index.js +6 -0
  22. package/factories/order/order.factory.js +115 -0
  23. package/factories/order-search/order-search.factory.js +79 -0
  24. package/factories/product/product.factory.js +23 -18
  25. package/factories/product-associations/product-associations.factory.js +25 -0
  26. package/factories/product-reviews/product-reviews.factory.js +65 -0
  27. package/factories/product-search/product-search.factory.js +3 -4
  28. package/factories/profile/profile.factory.js +61 -0
  29. package/index.js +9 -0
  30. package/package.json +11 -6
  31. package/schema/capabilities.schema.js +16 -2
  32. package/schema/configuration.schema.js +5 -1
  33. package/src/capabilities/cart.capability.d.ts +5 -0
  34. package/src/capabilities/checkout.capability.d.ts +30 -0
  35. package/src/capabilities/order-search.capability.d.ts +16 -0
  36. package/src/capabilities/order.capability.d.ts +12 -0
  37. package/src/capabilities/product-associations.capability.d.ts +23 -0
  38. package/src/capabilities/product-recommendations.capability.d.ts +24 -0
  39. package/src/capabilities/product-reviews.capability.d.ts +35 -0
  40. package/src/capabilities/profile.capability.d.ts +24 -0
  41. package/src/core/client.d.ts +77 -2
  42. package/src/core/initialize.types.d.ts +40 -7
  43. package/src/core/product-reviews.graphql.d.ts +10 -0
  44. package/src/factories/category/category.factory.d.ts +2 -2
  45. package/src/factories/checkout/checkout.factory.d.ts +32 -0
  46. package/src/factories/index.d.ts +6 -0
  47. package/src/factories/order/order.factory.d.ts +77 -0
  48. package/src/factories/order-search/order-search.factory.d.ts +43 -0
  49. package/src/factories/product/product.factory.d.ts +2 -1
  50. package/src/factories/product-associations/product-associations.factory.d.ts +15 -0
  51. package/src/factories/product-reviews/product-reviews.factory.d.ts +40 -0
  52. package/src/factories/profile/profile.factory.d.ts +43 -0
  53. package/src/index.d.ts +9 -0
  54. package/src/schema/capabilities.schema.d.ts +50 -2
  55. package/src/schema/configuration.schema.d.ts +7 -0
  56. package/src/schema/magento.types.d.ts +219 -0
  57. package/src/utils/magento-product-lookup.d.ts +15 -0
  58. package/src/utils/magento-product.d.ts +36 -0
  59. package/src/utils/magento-review.d.ts +20 -0
  60. package/utils/magento-product-lookup.js +76 -0
  61. package/utils/magento-product.js +110 -0
  62. package/utils/magento-review.js +34 -0
@@ -0,0 +1,150 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+ import {
12
+ OrderSearchCapability,
13
+ OrderSearchQueryByTermSchema,
14
+ OrderSearchResultSchema,
15
+ Reactionary,
16
+ success
17
+ } from "@reactionary/core";
18
+ import createDebug from "debug";
19
+ const debug = createDebug("reactionary:magento:order-search");
20
+ class MagentoOrderSearchCapability extends OrderSearchCapability {
21
+ constructor(config, cache, context, magentoApi, factory) {
22
+ super(cache, context);
23
+ this.magentoApi = magentoApi;
24
+ this.config = config;
25
+ this.factory = factory;
26
+ }
27
+ magentoApi;
28
+ config;
29
+ factory;
30
+ emptyResult(payload) {
31
+ return this.factory.parseOrderSearchResult(
32
+ this.context,
33
+ {
34
+ items: [],
35
+ total_count: 0,
36
+ search_criteria: {
37
+ page_size: payload.search.paginationOptions.pageSize,
38
+ current_page: payload.search.paginationOptions.pageNumber
39
+ }
40
+ },
41
+ payload
42
+ );
43
+ }
44
+ async resolveCustomerId() {
45
+ try {
46
+ const me = await this.magentoApi.getMe();
47
+ return me?.id !== void 0 ? String(me.id) : null;
48
+ } catch (err) {
49
+ debug("resolveCustomerId: not authenticated: %O", err);
50
+ return null;
51
+ }
52
+ }
53
+ buildSearchParams(payload, customerId) {
54
+ const params = new URLSearchParams();
55
+ let group = 0;
56
+ const addFilter = (field, value, condition = "eq") => {
57
+ params.set(
58
+ `searchCriteria[filterGroups][${group}][filters][0][field]`,
59
+ field
60
+ );
61
+ params.set(
62
+ `searchCriteria[filterGroups][${group}][filters][0][value]`,
63
+ value
64
+ );
65
+ params.set(
66
+ `searchCriteria[filterGroups][${group}][filters][0][condition_type]`,
67
+ condition
68
+ );
69
+ group += 1;
70
+ };
71
+ addFilter("customer_id", customerId);
72
+ if (payload.search.term) {
73
+ addFilter("increment_id", `%${payload.search.term}%`, "like");
74
+ }
75
+ if (payload.search.orderStatus && payload.search.orderStatus.length > 0) {
76
+ const magentoStatuses = Array.from(
77
+ new Set(
78
+ payload.search.orderStatus.flatMap((status) => {
79
+ switch (status) {
80
+ case "ReleasedToFulfillment":
81
+ return ["processing"];
82
+ case "Shipped":
83
+ return ["complete", "closed"];
84
+ case "Cancelled":
85
+ return ["canceled"];
86
+ default:
87
+ return ["pending"];
88
+ }
89
+ })
90
+ )
91
+ );
92
+ addFilter("status", magentoStatuses.join(","), "in");
93
+ }
94
+ if (payload.search.startDate) {
95
+ addFilter("created_at", payload.search.startDate, "gteq");
96
+ }
97
+ if (payload.search.endDate) {
98
+ addFilter("created_at", payload.search.endDate, "lteq");
99
+ }
100
+ params.set(
101
+ "searchCriteria[pageSize]",
102
+ String(payload.search.paginationOptions.pageSize)
103
+ );
104
+ params.set(
105
+ "searchCriteria[currentPage]",
106
+ String(payload.search.paginationOptions.pageNumber)
107
+ );
108
+ params.set("searchCriteria[sortOrders][0][field]", "created_at");
109
+ params.set("searchCriteria[sortOrders][0][direction]", "DESC");
110
+ return params;
111
+ }
112
+ async queryByTerm(payload) {
113
+ const customerId = await this.resolveCustomerId();
114
+ if (!customerId) {
115
+ return success(this.emptyResult(payload));
116
+ }
117
+ let response = await this.magentoApi.searchOrders(
118
+ this.buildSearchParams(payload, customerId)
119
+ );
120
+ if (payload.search.partNumber && payload.search.partNumber.length > 0) {
121
+ response = this.filterByPartNumber(response, payload.search.partNumber);
122
+ }
123
+ const result = this.factory.parseOrderSearchResult(
124
+ this.context,
125
+ response,
126
+ payload
127
+ );
128
+ return success(result);
129
+ }
130
+ filterByPartNumber(response, partNumbers) {
131
+ const items = (response.items ?? []).filter((order) => {
132
+ const skus = (order.items ?? []).map((i) => i.sku);
133
+ return partNumbers.every((pn) => skus.includes(pn));
134
+ });
135
+ return {
136
+ ...response,
137
+ items,
138
+ total_count: items.length
139
+ };
140
+ }
141
+ }
142
+ __decorateClass([
143
+ Reactionary({
144
+ inputSchema: OrderSearchQueryByTermSchema,
145
+ outputSchema: OrderSearchResultSchema
146
+ })
147
+ ], MagentoOrderSearchCapability.prototype, "queryByTerm", 1);
148
+ export {
149
+ MagentoOrderSearchCapability
150
+ };
@@ -0,0 +1,51 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+ import {
12
+ OrderCapability,
13
+ OrderQueryByIdSchema,
14
+ OrderSchema,
15
+ Reactionary,
16
+ error,
17
+ success
18
+ } from "@reactionary/core";
19
+ import createDebug from "debug";
20
+ const debug = createDebug("reactionary:magento:order");
21
+ class MagentoOrderCapability extends OrderCapability {
22
+ constructor(config, cache, context, magentoApi, factory) {
23
+ super(cache, context);
24
+ this.magentoApi = magentoApi;
25
+ this.config = config;
26
+ this.factory = factory;
27
+ }
28
+ magentoApi;
29
+ config;
30
+ factory;
31
+ async getById(payload) {
32
+ debug("getById %s", payload.order.key);
33
+ const data = await this.magentoApi.getOrderById(payload.order.key);
34
+ if (!data) {
35
+ return error({
36
+ type: "NotFound",
37
+ identifier: payload.order
38
+ });
39
+ }
40
+ return success(this.factory.parseOrder(this.context, data));
41
+ }
42
+ }
43
+ __decorateClass([
44
+ Reactionary({
45
+ inputSchema: OrderQueryByIdSchema,
46
+ outputSchema: OrderSchema
47
+ })
48
+ ], MagentoOrderCapability.prototype, "getById", 1);
49
+ export {
50
+ MagentoOrderCapability
51
+ };
@@ -5,8 +5,7 @@ var __decorateClass = (decorators, target, key, kind) => {
5
5
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
6
  if (decorator = decorators[i])
7
7
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
- if (kind && result)
9
- __defProp(target, key, result);
8
+ if (kind && result) __defProp(target, key, result);
10
9
  return result;
11
10
  };
12
11
  import {
@@ -26,6 +25,7 @@ class MagentoPriceCapability extends PriceCapability {
26
25
  this.config = config;
27
26
  this.factory = factory;
28
27
  }
28
+ magentoApi;
29
29
  config;
30
30
  factory;
31
31
  async getListPrice(payload) {
@@ -0,0 +1,118 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+ import {
12
+ ProductAssociationsCapability,
13
+ Reactionary,
14
+ success
15
+ } from "@reactionary/core";
16
+ import createDebug from "debug";
17
+ import {
18
+ fetchProductsBySkus,
19
+ resolveProductSku
20
+ } from "../utils/magento-product-lookup.js";
21
+ const debug = createDebug("reactionary:magento:product-associations");
22
+ class MagentoProductAssociationsCapability extends ProductAssociationsCapability {
23
+ constructor(config, cache, context, magentoApi, factory) {
24
+ super(cache, context);
25
+ this.magentoApi = magentoApi;
26
+ this.config = config;
27
+ this.factory = factory;
28
+ }
29
+ magentoApi;
30
+ config;
31
+ factory;
32
+ getAccessoriesLinkType() {
33
+ return "related";
34
+ }
35
+ getSparepartsLinkType() {
36
+ return "crosssell";
37
+ }
38
+ getReplacementsLinkType() {
39
+ return "upsell";
40
+ }
41
+ async fetchAssociatedProductsFor(forProduct, linkType, maxNumberOfAssociations) {
42
+ const sku = await resolveProductSku(this.magentoApi, forProduct.key);
43
+ if (!sku) {
44
+ return [];
45
+ }
46
+ try {
47
+ const links = await this.magentoApi.getProductLinks(sku, linkType);
48
+ const linkedSkus = [...links].sort((a, b) => (a.position ?? 0) - (b.position ?? 0)).map((link) => link.linked_product_sku).slice(0, maxNumberOfAssociations);
49
+ return await fetchProductsBySkus(this.magentoApi, linkedSkus);
50
+ } catch (err) {
51
+ debug("Failed to load %s links for %s: %O", linkType, sku, err);
52
+ return [];
53
+ }
54
+ }
55
+ toAssociations(forProduct, associationType, products) {
56
+ return products.map(
57
+ (product) => this.factory.parseAssociation(this.context, {
58
+ product,
59
+ identifier: {
60
+ key: `${forProduct.key}-${associationType}-${product.sku}`
61
+ }
62
+ })
63
+ );
64
+ }
65
+ async getAccessories(query) {
66
+ const products = await this.fetchAssociatedProductsFor(
67
+ query.forProduct,
68
+ this.getAccessoriesLinkType(),
69
+ query.numberOfAccessories
70
+ );
71
+ return success(this.toAssociations(query.forProduct, "accessory", products));
72
+ }
73
+ async getSpareparts(query) {
74
+ const products = await this.fetchAssociatedProductsFor(
75
+ query.forProduct,
76
+ this.getSparepartsLinkType(),
77
+ query.numberOfSpareparts
78
+ );
79
+ return success(this.toAssociations(query.forProduct, "sparepart", products));
80
+ }
81
+ async getReplacements(query) {
82
+ const products = await this.fetchAssociatedProductsFor(
83
+ query.forProduct,
84
+ this.getReplacementsLinkType(),
85
+ query.numberOfReplacements
86
+ );
87
+ return success(
88
+ this.toAssociations(query.forProduct, "replacement", products)
89
+ );
90
+ }
91
+ }
92
+ __decorateClass([
93
+ Reactionary({
94
+ cache: true,
95
+ cacheTimeToLiveInSeconds: 300,
96
+ currencyDependentCaching: false,
97
+ localeDependentCaching: false
98
+ })
99
+ ], MagentoProductAssociationsCapability.prototype, "getAccessories", 1);
100
+ __decorateClass([
101
+ Reactionary({
102
+ cache: true,
103
+ cacheTimeToLiveInSeconds: 300,
104
+ currencyDependentCaching: false,
105
+ localeDependentCaching: false
106
+ })
107
+ ], MagentoProductAssociationsCapability.prototype, "getSpareparts", 1);
108
+ __decorateClass([
109
+ Reactionary({
110
+ cache: true,
111
+ cacheTimeToLiveInSeconds: 300,
112
+ currencyDependentCaching: false,
113
+ localeDependentCaching: false
114
+ })
115
+ ], MagentoProductAssociationsCapability.prototype, "getReplacements", 1);
116
+ export {
117
+ MagentoProductAssociationsCapability
118
+ };
@@ -0,0 +1,148 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+ import {
12
+ ProductRecommendationsCapability,
13
+ Reactionary,
14
+ success
15
+ } from "@reactionary/core";
16
+ import createDebug from "debug";
17
+ import {
18
+ fetchProductsBySkus,
19
+ fetchProductsInCategory,
20
+ findCategoryByName,
21
+ resolveProductSku
22
+ } from "../utils/magento-product-lookup.js";
23
+ import { buildProductSearchResultItem } from "../utils/magento-product.js";
24
+ const debug = createDebug("reactionary:magento:product-recommendations");
25
+ class MagentoProductRecommendationsCapability extends ProductRecommendationsCapability {
26
+ constructor(config, cache, context, magentoApi) {
27
+ super(cache, context);
28
+ this.magentoApi = magentoApi;
29
+ this.config = config;
30
+ }
31
+ magentoApi;
32
+ config;
33
+ getRelatedLinkType() {
34
+ return "related";
35
+ }
36
+ getSimilarLinkType() {
37
+ return "upsell";
38
+ }
39
+ getFrequentlyBoughtTogetherLinkType() {
40
+ return "crosssell";
41
+ }
42
+ toRecommendations(algorithm, keyPrefix, products) {
43
+ return products.map(
44
+ (product) => ({
45
+ recommendationIdentifier: {
46
+ key: `${keyPrefix}_${product.sku}`,
47
+ algorithm
48
+ },
49
+ recommendationReturnType: "productSearchResultItem",
50
+ product: buildProductSearchResultItem(this.config, product)
51
+ })
52
+ );
53
+ }
54
+ async fetchLinkedProducts(sourceProduct, linkType, numberOfRecommendations) {
55
+ const sku = await resolveProductSku(this.magentoApi, sourceProduct.key);
56
+ if (!sku) {
57
+ return [];
58
+ }
59
+ try {
60
+ const links = await this.magentoApi.getProductLinks(sku, linkType);
61
+ const linkedSkus = [...links].sort((a, b) => (a.position ?? 0) - (b.position ?? 0)).map((link) => link.linked_product_sku).slice(0, numberOfRecommendations);
62
+ return await fetchProductsBySkus(this.magentoApi, linkedSkus);
63
+ } catch (err) {
64
+ debug("Failed to load %s links for %s: %O", linkType, sku, err);
65
+ return [];
66
+ }
67
+ }
68
+ async getCollection(query) {
69
+ const category = await findCategoryByName(
70
+ this.magentoApi,
71
+ query.collectionName
72
+ );
73
+ if (!category) {
74
+ debug("Collection not found: %s", query.collectionName);
75
+ return success([]);
76
+ }
77
+ try {
78
+ const products = await fetchProductsInCategory(
79
+ this.magentoApi,
80
+ String(category.id),
81
+ query.numberOfRecommendations
82
+ );
83
+ return success(
84
+ this.toRecommendations("collection", String(category.id), products)
85
+ );
86
+ } catch (err) {
87
+ debug("Failed to load products for collection %s: %O", query.collectionName, err);
88
+ return success([]);
89
+ }
90
+ }
91
+ async getRelatedProductsRecommendations(query) {
92
+ const products = await this.fetchLinkedProducts(
93
+ query.sourceProduct,
94
+ this.getRelatedLinkType(),
95
+ query.numberOfRecommendations
96
+ );
97
+ return this.toRecommendations("related", query.sourceProduct.key, products);
98
+ }
99
+ async getSimilarProductsRecommendations(query) {
100
+ const products = await this.fetchLinkedProducts(
101
+ query.sourceProduct,
102
+ this.getSimilarLinkType(),
103
+ query.numberOfRecommendations
104
+ );
105
+ return this.toRecommendations("similar", query.sourceProduct.key, products);
106
+ }
107
+ async getFrequentlyBoughtTogetherRecommendations(query) {
108
+ const products = await this.fetchLinkedProducts(
109
+ query.sourceProduct,
110
+ this.getFrequentlyBoughtTogetherLinkType(),
111
+ query.numberOfRecommendations
112
+ );
113
+ return this.toRecommendations(
114
+ "frequentlyBoughtTogether",
115
+ query.sourceProduct.key,
116
+ products
117
+ );
118
+ }
119
+ async getTrendingInCategoryRecommendations(query) {
120
+ const category = await findCategoryByName(
121
+ this.magentoApi,
122
+ query.sourceCategory.key
123
+ );
124
+ const categoryId = category ? String(category.id) : query.sourceCategory.key;
125
+ try {
126
+ const products = await fetchProductsInCategory(
127
+ this.magentoApi,
128
+ categoryId,
129
+ query.numberOfRecommendations
130
+ );
131
+ return this.toRecommendations("trendingInCategory", categoryId, products);
132
+ } catch (err) {
133
+ debug("Failed to load trending products for category %s: %O", categoryId, err);
134
+ return [];
135
+ }
136
+ }
137
+ }
138
+ __decorateClass([
139
+ Reactionary({
140
+ cache: true,
141
+ cacheTimeToLiveInSeconds: 300,
142
+ currencyDependentCaching: false,
143
+ localeDependentCaching: false
144
+ })
145
+ ], MagentoProductRecommendationsCapability.prototype, "getCollection", 1);
146
+ export {
147
+ MagentoProductRecommendationsCapability
148
+ };
@@ -0,0 +1,182 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+ import {
12
+ ProductRatingSummarySchema,
13
+ ProductReviewMutationSubmitSchema,
14
+ ProductReviewPaginatedResultSchema,
15
+ ProductReviewSchema,
16
+ ProductReviewsCapability,
17
+ ProductReviewsGetRatingSummaryQuerySchema,
18
+ ProductReviewsListQuerySchema,
19
+ Reactionary,
20
+ error,
21
+ success
22
+ } from "@reactionary/core";
23
+ import createDebug from "debug";
24
+ import { resolveProductSku } from "../utils/magento-product-lookup.js";
25
+ const debug = createDebug("reactionary:magento:product-reviews");
26
+ const DEFAULT_PAGE_SIZE = 20;
27
+ const DEFAULT_REVIEW_RATING_CODE = "Rating";
28
+ class MagentoProductReviewsCapability extends ProductReviewsCapability {
29
+ constructor(config, cache, context, magentoApi, factory) {
30
+ super(cache, context);
31
+ this.magentoApi = magentoApi;
32
+ this.config = config;
33
+ this.factory = factory;
34
+ }
35
+ magentoApi;
36
+ config;
37
+ factory;
38
+ /**
39
+ * The name of the Magento rating that carries the overall star score. Stores
40
+ * can define several named ratings; override to pick a different one.
41
+ */
42
+ getReviewRatingCode() {
43
+ return this.config.reviewRatingCode ?? DEFAULT_REVIEW_RATING_CODE;
44
+ }
45
+ async fetchRatingSummary(sku) {
46
+ try {
47
+ return await this.magentoApi.getProductReviewSummary(sku);
48
+ } catch (err) {
49
+ debug("Failed to load the rating summary for %s: %O", sku, err);
50
+ return null;
51
+ }
52
+ }
53
+ async fetchReviews(sku, pageSize, pageNumber) {
54
+ try {
55
+ return await this.magentoApi.getProductReviews(sku, pageSize, pageNumber);
56
+ } catch (err) {
57
+ debug("Failed to load reviews for %s: %O", sku, err);
58
+ return null;
59
+ }
60
+ }
61
+ /**
62
+ * Magento will not accept a star count directly — the rating has to be sent
63
+ * as an opaque `value_id` looked up through `productReviewRatingsMetadata`.
64
+ */
65
+ async resolveRatingInput(rating) {
66
+ const metadata = await this.magentoApi.getProductReviewRatingsMetadata();
67
+ const wantedCode = this.getReviewRatingCode().toLowerCase();
68
+ const entry = metadata.find((item) => item.name.toLowerCase() === wantedCode) ?? metadata[0];
69
+ if (!entry) {
70
+ return null;
71
+ }
72
+ const wantedValue = String(Math.round(rating));
73
+ const value = entry.values.find((item) => item.value === wantedValue);
74
+ if (!value) {
75
+ return null;
76
+ }
77
+ return [{ id: entry.id, value_id: value.value_id }];
78
+ }
79
+ async getRatingSummary(query) {
80
+ const sku = await resolveProductSku(this.magentoApi, query.product.key);
81
+ const product = sku ? await this.fetchRatingSummary(sku) : null;
82
+ return success(
83
+ this.factory.parseRatingSummary(this.context, {
84
+ product: query.product,
85
+ ratingSummary: product?.rating_summary,
86
+ reviewCount: product?.review_count
87
+ })
88
+ );
89
+ }
90
+ async findReviews(query) {
91
+ const pageSize = query.paginationOptions?.pageSize ?? DEFAULT_PAGE_SIZE;
92
+ const pageNumber = query.paginationOptions?.pageNumber ?? 1;
93
+ const sku = await resolveProductSku(this.magentoApi, query.product.key);
94
+ const product = sku ? await this.fetchReviews(sku, pageSize, pageNumber) : null;
95
+ const reviews = product?.reviews?.items ?? [];
96
+ return success(
97
+ this.factory.parseReviewPaginatedResult(this.context, {
98
+ product: query.product,
99
+ sku: sku ?? query.product.key,
100
+ reviews,
101
+ totalCount: product?.review_count ?? reviews.length,
102
+ pageSize,
103
+ pageNumber
104
+ })
105
+ );
106
+ }
107
+ async submitReview(mutation) {
108
+ if (this.context.session.identityContext.identity.type !== "Registered") {
109
+ return error({
110
+ type: "InvalidInput",
111
+ error: "Only registered users can submit reviews."
112
+ });
113
+ }
114
+ const sku = await resolveProductSku(this.magentoApi, mutation.product.key);
115
+ if (!sku) {
116
+ return error({
117
+ type: "NotFound",
118
+ identifier: mutation.product
119
+ });
120
+ }
121
+ const ratings = await this.resolveRatingInput(mutation.rating);
122
+ if (!ratings) {
123
+ return error({
124
+ type: "Generic",
125
+ message: `Magento has no review rating "${this.getReviewRatingCode()}" with a value of ${mutation.rating}. Check the store's review rating configuration.`
126
+ });
127
+ }
128
+ const review = await this.magentoApi.createProductReview({
129
+ sku,
130
+ nickname: mutation.authorName,
131
+ summary: mutation.title,
132
+ text: mutation.content,
133
+ ratings
134
+ });
135
+ if (!review) {
136
+ return error({
137
+ type: "Generic",
138
+ message: `Magento accepted the review for ${sku} but returned no review payload.`
139
+ });
140
+ }
141
+ return success(
142
+ this.factory.parseReview(this.context, {
143
+ product: mutation.product,
144
+ sku,
145
+ review
146
+ })
147
+ );
148
+ }
149
+ }
150
+ __decorateClass([
151
+ Reactionary({
152
+ inputSchema: ProductReviewsGetRatingSummaryQuerySchema,
153
+ outputSchema: ProductRatingSummarySchema,
154
+ cache: true,
155
+ cacheTimeToLiveInSeconds: 300,
156
+ currencyDependentCaching: false,
157
+ localeDependentCaching: false
158
+ })
159
+ ], MagentoProductReviewsCapability.prototype, "getRatingSummary", 1);
160
+ __decorateClass([
161
+ Reactionary({
162
+ inputSchema: ProductReviewsListQuerySchema,
163
+ outputSchema: ProductReviewPaginatedResultSchema,
164
+ cache: true,
165
+ cacheTimeToLiveInSeconds: 60,
166
+ currencyDependentCaching: false,
167
+ localeDependentCaching: true
168
+ })
169
+ ], MagentoProductReviewsCapability.prototype, "findReviews", 1);
170
+ __decorateClass([
171
+ Reactionary({
172
+ inputSchema: ProductReviewMutationSubmitSchema,
173
+ outputSchema: ProductReviewSchema,
174
+ cache: false,
175
+ cacheTimeToLiveInSeconds: 0,
176
+ currencyDependentCaching: false,
177
+ localeDependentCaching: false
178
+ })
179
+ ], MagentoProductReviewsCapability.prototype, "submitReview", 1);
180
+ export {
181
+ MagentoProductReviewsCapability
182
+ };
@@ -5,8 +5,7 @@ var __decorateClass = (decorators, target, key, kind) => {
5
5
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
6
  if (decorator = decorators[i])
7
7
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
- if (kind && result)
9
- __defProp(target, key, result);
8
+ if (kind && result) __defProp(target, key, result);
10
9
  return result;
11
10
  };
12
11
  import {
@@ -27,6 +26,7 @@ class MagentoProductSearchCapability extends ProductSearchCapability {
27
26
  this.config = config;
28
27
  this.factory = factory;
29
28
  }
29
+ magentoApi;
30
30
  config;
31
31
  factory;
32
32
  async queryByTerm(payload) {