@medusajs/product 3.0.0-preview-20250410210150 → 3.0.0-preview-20251201152819

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 (111) hide show
  1. package/dist/joiner-config.d.ts.map +1 -1
  2. package/dist/joiner-config.js +1 -0
  3. package/dist/joiner-config.js.map +1 -1
  4. package/dist/migrations/InitialSetup20240401153642.d.ts +1 -1
  5. package/dist/migrations/InitialSetup20240401153642.d.ts.map +1 -1
  6. package/dist/migrations/InitialSetup20240401153642.js +1 -1
  7. package/dist/migrations/InitialSetup20240401153642.js.map +1 -1
  8. package/dist/migrations/Migration20240601111544.d.ts +1 -1
  9. package/dist/migrations/Migration20240601111544.d.ts.map +1 -1
  10. package/dist/migrations/Migration20240601111544.js +1 -1
  11. package/dist/migrations/Migration20240601111544.js.map +1 -1
  12. package/dist/migrations/Migration202408271511.d.ts +1 -1
  13. package/dist/migrations/Migration202408271511.d.ts.map +1 -1
  14. package/dist/migrations/Migration202408271511.js +1 -1
  15. package/dist/migrations/Migration202408271511.js.map +1 -1
  16. package/dist/migrations/Migration20241122120331.d.ts +1 -1
  17. package/dist/migrations/Migration20241122120331.d.ts.map +1 -1
  18. package/dist/migrations/Migration20241122120331.js +1 -1
  19. package/dist/migrations/Migration20241122120331.js.map +1 -1
  20. package/dist/migrations/Migration20241125090957.d.ts +1 -1
  21. package/dist/migrations/Migration20241125090957.d.ts.map +1 -1
  22. package/dist/migrations/Migration20241125090957.js +1 -1
  23. package/dist/migrations/Migration20241125090957.js.map +1 -1
  24. package/dist/migrations/Migration20250411073236.d.ts +6 -0
  25. package/dist/migrations/Migration20250411073236.d.ts.map +1 -0
  26. package/dist/migrations/Migration20250411073236.js +14 -0
  27. package/dist/migrations/Migration20250411073236.js.map +1 -0
  28. package/dist/migrations/Migration20250516081326.d.ts +6 -0
  29. package/dist/migrations/Migration20250516081326.d.ts.map +1 -0
  30. package/dist/migrations/Migration20250516081326.js +14 -0
  31. package/dist/migrations/Migration20250516081326.js.map +1 -0
  32. package/dist/migrations/Migration20250910154539.d.ts +6 -0
  33. package/dist/migrations/Migration20250910154539.d.ts.map +1 -0
  34. package/dist/migrations/Migration20250910154539.js +25 -0
  35. package/dist/migrations/Migration20250910154539.js.map +1 -0
  36. package/dist/migrations/Migration20250911092221.d.ts +6 -0
  37. package/dist/migrations/Migration20250911092221.d.ts.map +1 -0
  38. package/dist/migrations/Migration20250911092221.js +14 -0
  39. package/dist/migrations/Migration20250911092221.js.map +1 -0
  40. package/dist/migrations/Migration20250929204438.d.ts +6 -0
  41. package/dist/migrations/Migration20250929204438.d.ts.map +1 -0
  42. package/dist/migrations/Migration20250929204438.js +27 -0
  43. package/dist/migrations/Migration20250929204438.js.map +1 -0
  44. package/dist/migrations/Migration20251008132218.d.ts +6 -0
  45. package/dist/migrations/Migration20251008132218.d.ts.map +1 -0
  46. package/dist/migrations/Migration20251008132218.js +14 -0
  47. package/dist/migrations/Migration20251008132218.js.map +1 -0
  48. package/dist/migrations/Migration20251011090511.d.ts +6 -0
  49. package/dist/migrations/Migration20251011090511.d.ts.map +1 -0
  50. package/dist/migrations/Migration20251011090511.js +16 -0
  51. package/dist/migrations/Migration20251011090511.js.map +1 -0
  52. package/dist/models/index.d.ts +1 -0
  53. package/dist/models/index.d.ts.map +1 -1
  54. package/dist/models/index.js +3 -1
  55. package/dist/models/index.js.map +1 -1
  56. package/dist/models/product-category.d.ts +113 -17
  57. package/dist/models/product-category.d.ts.map +1 -1
  58. package/dist/models/product-collection.d.ts +112 -16
  59. package/dist/models/product-collection.d.ts.map +1 -1
  60. package/dist/models/product-image.d.ts +418 -17
  61. package/dist/models/product-image.d.ts.map +1 -1
  62. package/dist/models/product-image.js +27 -0
  63. package/dist/models/product-image.js.map +1 -1
  64. package/dist/models/product-option-value.d.ts +369 -28
  65. package/dist/models/product-option-value.d.ts.map +1 -1
  66. package/dist/models/product-option.d.ts +326 -15
  67. package/dist/models/product-option.d.ts.map +1 -1
  68. package/dist/models/product-tag.d.ts +113 -17
  69. package/dist/models/product-tag.d.ts.map +1 -1
  70. package/dist/models/product-type.d.ts +112 -16
  71. package/dist/models/product-type.d.ts.map +1 -1
  72. package/dist/models/product-variant-product-image.d.ts +1015 -0
  73. package/dist/models/product-variant-product-image.d.ts.map +1 -0
  74. package/dist/models/product-variant-product-image.js +22 -0
  75. package/dist/models/product-variant-product-image.js.map +1 -0
  76. package/dist/models/product-variant.d.ts +305 -28
  77. package/dist/models/product-variant.d.ts.map +1 -1
  78. package/dist/models/product-variant.js +21 -1
  79. package/dist/models/product-variant.js.map +1 -1
  80. package/dist/models/product.d.ts +113 -17
  81. package/dist/models/product.d.ts.map +1 -1
  82. package/dist/models/product.js +6 -0
  83. package/dist/models/product.js.map +1 -1
  84. package/dist/repositories/product-category.d.ts +397 -40
  85. package/dist/repositories/product-category.d.ts.map +1 -1
  86. package/dist/repositories/product-category.js +4 -6
  87. package/dist/repositories/product-category.js.map +1 -1
  88. package/dist/repositories/product.d.ts +119 -19
  89. package/dist/repositories/product.d.ts.map +1 -1
  90. package/dist/repositories/product.js +108 -1
  91. package/dist/repositories/product.js.map +1 -1
  92. package/dist/schema/index.d.ts +1 -1
  93. package/dist/schema/index.d.ts.map +1 -1
  94. package/dist/schema/index.js +2 -0
  95. package/dist/schema/index.js.map +1 -1
  96. package/dist/services/product-category.d.ts +9 -2
  97. package/dist/services/product-category.d.ts.map +1 -1
  98. package/dist/services/product-category.js +46 -9
  99. package/dist/services/product-category.js.map +1 -1
  100. package/dist/services/product-module-service.d.ts +42 -4
  101. package/dist/services/product-module-service.d.ts.map +1 -1
  102. package/dist/services/product-module-service.js +494 -211
  103. package/dist/services/product-module-service.js.map +1 -1
  104. package/dist/tsconfig.tsbuildinfo +1 -1
  105. package/dist/types/index.d.ts +5 -0
  106. package/dist/types/index.d.ts.map +1 -1
  107. package/dist/utils/events.d.ts +0 -168
  108. package/dist/utils/events.d.ts.map +1 -1
  109. package/dist/utils/events.js +0 -126
  110. package/dist/utils/events.js.map +1 -1
  111. package/package.json +14 -29
@@ -11,13 +11,13 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  return function (target, key) { decorator(target, key, paramIndex); }
13
13
  };
14
- var _a, _b;
14
+ var _a;
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
16
  const types_1 = require("@medusajs/framework/types");
17
17
  const _models_1 = require("../models");
18
18
  const utils_1 = require("@medusajs/framework/utils");
19
- const utils_2 = require("../utils");
20
19
  const joiner_config_1 = require("./../joiner-config");
20
+ const events_1 = require("../utils/events");
21
21
  class ProductModuleService extends (0, utils_1.MedusaService)({
22
22
  Product: _models_1.Product,
23
23
  ProductCategory: _models_1.ProductCategory,
@@ -27,13 +27,15 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
27
27
  ProductTag: _models_1.ProductTag,
28
28
  ProductType: _models_1.ProductType,
29
29
  ProductVariant: _models_1.ProductVariant,
30
+ ProductImage: _models_1.ProductImage,
30
31
  }) {
31
- constructor({ baseRepository, productService, productVariantService, productTagService, productCategoryService, productCollectionService, productImageService, productTypeService, productOptionService, productOptionValueService, [utils_1.Modules.EVENT_BUS]: eventBusModuleService, }, moduleDeclaration) {
32
+ constructor({ baseRepository, productRepository, productService, productVariantService, productTagService, productCategoryService, productCollectionService, productImageService, productTypeService, productOptionService, productOptionValueService, productVariantProductImageService, [utils_1.Modules.EVENT_BUS]: eventBusModuleService, }, moduleDeclaration) {
32
33
  // @ts-ignore
33
34
  // eslint-disable-next-line prefer-rest-params
34
35
  super(...arguments);
35
36
  this.moduleDeclaration = moduleDeclaration;
36
37
  this.baseRepository_ = baseRepository;
38
+ this.productRepository_ = productRepository;
37
39
  this.productService_ = productService;
38
40
  this.productVariantService_ = productVariantService;
39
41
  this.productTagService_ = productTagService;
@@ -43,6 +45,7 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
43
45
  this.productTypeService_ = productTypeService;
44
46
  this.productOptionService_ = productOptionService;
45
47
  this.productOptionValueService_ = productOptionValueService;
48
+ this.productVariantProductImageService_ = productVariantProductImageService;
46
49
  this.eventBusModuleService_ = eventBusModuleService;
47
50
  }
48
51
  __joinerConfig() {
@@ -50,17 +53,63 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
50
53
  }
51
54
  // @ts-ignore
52
55
  async retrieveProduct(productId, config, sharedContext) {
53
- const product = await this.productService_.retrieve(productId, this.getProductFindConfig_(config), sharedContext);
56
+ const relationsSet = new Set(config?.relations ?? []);
57
+ const shouldLoadVariantImages = relationsSet.has("variants.images");
58
+ if (shouldLoadVariantImages) {
59
+ relationsSet.add("variants");
60
+ relationsSet.add("images");
61
+ }
62
+ const product = await this.productService_.retrieve(productId, this.getProductFindConfig_({
63
+ ...config,
64
+ relations: Array.from(relationsSet),
65
+ }), sharedContext);
66
+ if (shouldLoadVariantImages && product.variants && product.images) {
67
+ await this.buildVariantImagesFromProduct(product.variants, product.images, sharedContext);
68
+ }
54
69
  return this.baseRepository_.serialize(product);
55
70
  }
56
71
  // @ts-ignore
57
72
  async listProducts(filters, config, sharedContext) {
58
- const products = await this.productService_.list(filters, this.getProductFindConfig_(config), sharedContext);
73
+ const relationsSet = new Set(config?.relations ?? []);
74
+ const shouldLoadVariantImages = relationsSet.has("variants.images");
75
+ if (shouldLoadVariantImages) {
76
+ relationsSet.add("variants");
77
+ relationsSet.add("images");
78
+ }
79
+ const products = await this.productService_.list(filters, this.getProductFindConfig_({
80
+ ...config,
81
+ relations: Array.from(relationsSet),
82
+ }), sharedContext);
83
+ if (shouldLoadVariantImages) {
84
+ for (const product of products) {
85
+ if (product.variants && product.images) {
86
+ await this.buildVariantImagesFromProduct(product.variants, product.images, sharedContext);
87
+ }
88
+ }
89
+ }
59
90
  return this.baseRepository_.serialize(products);
60
91
  }
61
92
  // @ts-ignore
62
93
  async listAndCountProducts(filters, config, sharedContext) {
63
- const [products, count] = await this.productService_.listAndCount(filters, this.getProductFindConfig_(config), sharedContext);
94
+ const shouldLoadVariantImages = config?.relations?.includes("variants.images");
95
+ // Ensure we load necessary relations
96
+ const relations = [...(config?.relations || [])];
97
+ if (shouldLoadVariantImages) {
98
+ if (!relations.includes("variants")) {
99
+ relations.push("variants");
100
+ }
101
+ if (!relations.includes("images")) {
102
+ relations.push("images");
103
+ }
104
+ }
105
+ const [products, count] = await this.productService_.listAndCount(filters, this.getProductFindConfig_({ ...config, relations }), sharedContext);
106
+ if (shouldLoadVariantImages) {
107
+ for (const product of products) {
108
+ if (product.variants && product.images) {
109
+ await this.buildVariantImagesFromProduct(product.variants, product.images, sharedContext);
110
+ }
111
+ }
112
+ }
64
113
  const serializedProducts = await this.baseRepository_.serialize(products);
65
114
  return [serializedProducts, count];
66
115
  }
@@ -105,10 +154,6 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
105
154
  const productVariantsWithOptions = ProductModuleService.assignOptionsToVariants(data, productOptions);
106
155
  ProductModuleService.checkIfVariantWithOptionsAlreadyExists(productVariantsWithOptions, variants);
107
156
  const createdVariants = await this.productVariantService_.create(productVariantsWithOptions, sharedContext);
108
- utils_2.eventBuilders.createdProductVariant({
109
- data: createdVariants,
110
- sharedContext,
111
- });
112
157
  return createdVariants;
113
158
  }
114
159
  async upsertProductVariants(data, sharedContext = {}) {
@@ -118,7 +163,7 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
118
163
  let created = [];
119
164
  let updated = [];
120
165
  if (forCreate.length) {
121
- created = await this.createVariants_(forCreate, sharedContext);
166
+ created = await this.createProductVariants(forCreate, sharedContext);
122
167
  }
123
168
  if (forUpdate.length) {
124
169
  updated = await this.updateVariants_(forUpdate, sharedContext);
@@ -165,21 +210,9 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
165
210
  if (data.some((d) => !!d.options)) {
166
211
  ProductModuleService.checkIfVariantWithOptionsAlreadyExists(productVariantsWithOptions, allVariants);
167
212
  }
168
- const { entities: productVariants, performedActions } = await this.productVariantService_.upsertWithReplace(productVariantsWithOptions, {
213
+ const { entities: productVariants } = await this.productVariantService_.upsertWithReplace(productVariantsWithOptions, {
169
214
  relations: ["options"],
170
215
  }, sharedContext);
171
- utils_2.eventBuilders.createdProductVariant({
172
- data: performedActions.created[_models_1.ProductVariant.name] ?? [],
173
- sharedContext,
174
- });
175
- utils_2.eventBuilders.updatedProductVariant({
176
- data: performedActions.updated[_models_1.ProductVariant.name] ?? [],
177
- sharedContext,
178
- });
179
- utils_2.eventBuilders.deletedProductVariant({
180
- data: performedActions.deleted[_models_1.ProductVariant.name] ?? [],
181
- sharedContext,
182
- });
183
216
  return productVariants;
184
217
  }
185
218
  // @ts-expect-error
@@ -187,13 +220,14 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
187
220
  const input = Array.isArray(data) ? data : [data];
188
221
  const tags = await this.productTagService_.create(input, sharedContext);
189
222
  const createdTags = await this.baseRepository_.serialize(tags);
190
- utils_2.eventBuilders.createdProductTag({
191
- data: createdTags,
192
- sharedContext,
193
- });
194
223
  return Array.isArray(data) ? createdTags : createdTags[0];
195
224
  }
196
225
  async upsertProductTags(data, sharedContext = {}) {
226
+ const tags = await this.upsertProductTags_(data, sharedContext);
227
+ const allTags = await this.baseRepository_.serialize(Array.isArray(data) ? tags : tags[0]);
228
+ return allTags;
229
+ }
230
+ async upsertProductTags_(data, sharedContext = {}) {
197
231
  const input = Array.isArray(data) ? data : [data];
198
232
  const forUpdate = input.filter((tag) => !!tag.id);
199
233
  const forCreate = input.filter((tag) => !tag.id);
@@ -201,21 +235,11 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
201
235
  let updated = [];
202
236
  if (forCreate.length) {
203
237
  created = await this.productTagService_.create(forCreate, sharedContext);
204
- utils_2.eventBuilders.createdProductTag({
205
- data: created,
206
- sharedContext,
207
- });
208
238
  }
209
239
  if (forUpdate.length) {
210
240
  updated = await this.productTagService_.update(forUpdate, sharedContext);
211
- utils_2.eventBuilders.updatedProductTag({
212
- data: updated,
213
- sharedContext,
214
- });
215
241
  }
216
- const result = [...created, ...updated];
217
- const allTags = await this.baseRepository_.serialize(result);
218
- return Array.isArray(data) ? allTags : allTags[0];
242
+ return [...created, ...updated];
219
243
  }
220
244
  // @ts-expect-error
221
245
  async updateProductTags(idOrSelector, data, sharedContext = {}) {
@@ -234,10 +258,6 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
234
258
  }
235
259
  const tags = await this.productTagService_.update(normalizedInput, sharedContext);
236
260
  const updatedTags = await this.baseRepository_.serialize(tags);
237
- utils_2.eventBuilders.updatedProductTag({
238
- data: updatedTags,
239
- sharedContext,
240
- });
241
261
  return (0, utils_1.isString)(idOrSelector) ? updatedTags[0] : updatedTags;
242
262
  }
243
263
  // @ts-expect-error
@@ -248,6 +268,11 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
248
268
  return Array.isArray(data) ? createdTypes : createdTypes[0];
249
269
  }
250
270
  async upsertProductTypes(data, sharedContext = {}) {
271
+ const types = await this.upsertProductTypes_(data, sharedContext);
272
+ const result = await this.baseRepository_.serialize(types);
273
+ return Array.isArray(data) ? result : result[0];
274
+ }
275
+ async upsertProductTypes_(data, sharedContext) {
251
276
  const input = Array.isArray(data) ? data : [data];
252
277
  const forUpdate = input.filter((type) => !!type.id);
253
278
  const forCreate = input.filter((type) => !type.id);
@@ -259,9 +284,7 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
259
284
  if (forUpdate.length) {
260
285
  updated = await this.productTypeService_.update(forUpdate, sharedContext);
261
286
  }
262
- const result = [...created, ...updated];
263
- const allTypes = await this.baseRepository_.serialize(result);
264
- return Array.isArray(data) ? allTypes : allTypes[0];
287
+ return [...created, ...updated];
265
288
  }
266
289
  // @ts-expect-error
267
290
  async updateProductTypes(idOrSelector, data, sharedContext = {}) {
@@ -382,10 +405,6 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
382
405
  const input = Array.isArray(data) ? data : [data];
383
406
  const collections = await this.createCollections_(input, sharedContext);
384
407
  const createdCollections = await this.baseRepository_.serialize(collections);
385
- utils_2.eventBuilders.createdProductCollection({
386
- data: collections,
387
- sharedContext,
388
- });
389
408
  return Array.isArray(data) ? createdCollections : createdCollections[0];
390
409
  }
391
410
  async createCollections_(data, sharedContext = {}) {
@@ -396,6 +415,13 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
396
415
  return productCollections;
397
416
  }
398
417
  async upsertProductCollections(data, sharedContext = {}) {
418
+ const collections = await this.upsertCollections_(data, sharedContext);
419
+ const serializedCollections = await this.baseRepository_.serialize(collections);
420
+ return Array.isArray(data)
421
+ ? serializedCollections
422
+ : serializedCollections[0];
423
+ }
424
+ async upsertCollections_(data, sharedContext = {}) {
399
425
  const input = Array.isArray(data) ? data : [data];
400
426
  const forUpdate = input.filter((collection) => !!collection.id);
401
427
  const forCreate = input.filter((collection) => !collection.id);
@@ -407,21 +433,7 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
407
433
  if (forUpdate.length) {
408
434
  updated = await this.updateCollections_(forUpdate, sharedContext);
409
435
  }
410
- const result = [...created, ...updated];
411
- const allCollections = await this.baseRepository_.serialize(result);
412
- if (created.length) {
413
- utils_2.eventBuilders.createdProductCollection({
414
- data: created,
415
- sharedContext,
416
- });
417
- }
418
- if (updated.length) {
419
- utils_2.eventBuilders.updatedProductCollection({
420
- data: updated,
421
- sharedContext,
422
- });
423
- }
424
- return Array.isArray(data) ? allCollections : allCollections[0];
436
+ return [...created, ...updated];
425
437
  }
426
438
  // @ts-expect-error
427
439
  async updateProductCollections(idOrSelector, data, sharedContext = {}) {
@@ -439,10 +451,6 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
439
451
  }
440
452
  const collections = await this.updateCollections_(normalizedInput, sharedContext);
441
453
  const updatedCollections = await this.baseRepository_.serialize(collections);
442
- utils_2.eventBuilders.updatedProductCollection({
443
- data: updatedCollections,
444
- sharedContext,
445
- });
446
454
  return (0, utils_1.isString)(idOrSelector) ? updatedCollections[0] : updatedCollections;
447
455
  }
448
456
  async updateCollections_(data, sharedContext = {}) {
@@ -451,31 +459,29 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
451
459
  // Another alternative is to not allow passing product_ids to a collection, and instead set the collection_id through the product update call.
452
460
  const updatedCollections = await this.productCollectionService_.update(normalizedInput.map((c) => (0, utils_1.removeUndefined)({ ...c, products: undefined })), sharedContext);
453
461
  const collections = [];
454
- const updateSelectorAndData = updatedCollections.flatMap((collectionData) => {
462
+ const toUpdate = [];
463
+ updatedCollections.forEach((collectionData) => {
455
464
  const input = normalizedInput.find((c) => c.id === collectionData.id);
456
465
  const productsToUpdate = input?.products;
457
466
  const dissociateSelector = {
458
467
  collection_id: collectionData.id,
459
468
  };
460
469
  const associateSelector = {};
461
- if (!!productsToUpdate?.length) {
470
+ if ((0, utils_1.isDefined)(productsToUpdate)) {
462
471
  const productIds = productsToUpdate.map((p) => p.id);
463
472
  dissociateSelector["id"] = { $nin: productIds };
464
473
  associateSelector["id"] = { $in: productIds };
465
474
  }
466
- else if (!(0, utils_1.isDefined)(productsToUpdate)) {
467
- return [];
468
- }
469
- const result = [
470
- {
475
+ if ((0, utils_1.isPresent)(dissociateSelector["id"])) {
476
+ toUpdate.push({
471
477
  selector: dissociateSelector,
472
478
  data: {
473
479
  collection_id: null,
474
480
  },
475
- },
476
- ];
477
- if ((0, utils_1.isPresent)(associateSelector)) {
478
- result.push({
481
+ });
482
+ }
483
+ if ((0, utils_1.isPresent)(associateSelector["id"])) {
484
+ toUpdate.push({
479
485
  selector: associateSelector,
480
486
  data: {
481
487
  collection_id: collectionData.id,
@@ -486,10 +492,9 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
486
492
  ...collectionData,
487
493
  products: productsToUpdate ?? [],
488
494
  });
489
- return result;
490
495
  });
491
- if (updateSelectorAndData.length) {
492
- await this.productService_.update(updateSelectorAndData, sharedContext);
496
+ if (toUpdate.length) {
497
+ await this.productService_.update(toUpdate, sharedContext);
493
498
  }
494
499
  return collections;
495
500
  }
@@ -501,39 +506,65 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
501
506
  });
502
507
  const categories = await this.productCategoryService_.create(input, sharedContext);
503
508
  const createdCategories = await this.baseRepository_.serialize(categories);
504
- utils_2.eventBuilders.createdProductCategory({
509
+ // TODO: Same as the update categories, for some reason I cant get the tree repository update
510
+ events_1.eventBuilders.createdProductCategory({
505
511
  data: createdCategories,
506
512
  sharedContext,
507
513
  });
508
514
  return Array.isArray(data) ? createdCategories : createdCategories[0];
509
515
  }
510
516
  async upsertProductCategories(data, sharedContext = {}) {
517
+ const categories = await this.upsertProductCategories_(data, sharedContext);
518
+ const serializedCategories = await this.baseRepository_.serialize(categories);
519
+ return Array.isArray(data) ? serializedCategories : serializedCategories[0];
520
+ }
521
+ async upsertProductCategories_(data, sharedContext = {}) {
511
522
  const input = Array.isArray(data) ? data : [data];
512
523
  const forUpdate = input.filter((category) => !!category.id);
513
- const forCreate = input.filter((category) => !category.id);
524
+ let forCreate = input.filter((category) => !category.id);
514
525
  let created = [];
515
526
  let updated = [];
516
527
  if (forCreate.length) {
528
+ forCreate = forCreate.map((productCategory) => {
529
+ productCategory.handle ??= (0, utils_1.kebabCase)(productCategory.name);
530
+ return productCategory;
531
+ });
517
532
  created = await this.productCategoryService_.create(forCreate, sharedContext);
518
533
  }
519
534
  if (forUpdate.length) {
520
535
  updated = await this.productCategoryService_.update(forUpdate, sharedContext);
521
536
  }
522
- const createdCategories = await this.baseRepository_.serialize(created);
523
- const updatedCategories = await this.baseRepository_.serialize(updated);
524
- utils_2.eventBuilders.createdProductCategory({
525
- data: createdCategories,
526
- sharedContext,
527
- });
528
- utils_2.eventBuilders.updatedProductCategory({
529
- data: updatedCategories,
530
- sharedContext,
531
- });
532
- const result = [...createdCategories, ...updatedCategories];
533
- return Array.isArray(data) ? result : result[0];
537
+ // TODO: Same as the update categories, for some reason I cant get the tree repository update
538
+ // event. I ll need to investigate this
539
+ if (created.length) {
540
+ events_1.eventBuilders.createdProductCategory({
541
+ data: created,
542
+ sharedContext,
543
+ });
544
+ }
545
+ if (updated.length) {
546
+ events_1.eventBuilders.updatedProductCategory({
547
+ data: updated,
548
+ sharedContext,
549
+ });
550
+ }
551
+ return [...created, ...updated];
534
552
  }
535
553
  // @ts-expect-error
536
554
  async updateProductCategories(idOrSelector, data, sharedContext = {}) {
555
+ const categories = await this.updateProductCategories_(idOrSelector, data, sharedContext);
556
+ const serializedCategories = await this.baseRepository_.serialize(categories);
557
+ // TODO: for some reason I cant get the tree repository update
558
+ // event. I ll need to investigate this
559
+ events_1.eventBuilders.updatedProductCategory({
560
+ data: serializedCategories,
561
+ sharedContext,
562
+ });
563
+ return (0, utils_1.isString)(idOrSelector)
564
+ ? serializedCategories[0]
565
+ : serializedCategories;
566
+ }
567
+ async updateProductCategories_(idOrSelector, data, sharedContext = {}) {
537
568
  let normalizedInput = [];
538
569
  if ((0, utils_1.isString)(idOrSelector)) {
539
570
  // Check if the type exists in the first place
@@ -548,22 +579,13 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
548
579
  }));
549
580
  }
550
581
  const categories = await this.productCategoryService_.update(normalizedInput, sharedContext);
551
- const updatedCategories = await this.baseRepository_.serialize(categories);
552
- utils_2.eventBuilders.updatedProductCategory({
553
- data: updatedCategories,
554
- sharedContext,
555
- });
556
- return (0, utils_1.isString)(idOrSelector) ? updatedCategories[0] : updatedCategories;
582
+ return categories;
557
583
  }
558
584
  // @ts-expect-error
559
585
  async createProducts(data, sharedContext = {}) {
560
586
  const input = Array.isArray(data) ? data : [data];
561
587
  const products = await this.createProducts_(input, sharedContext);
562
588
  const createdProducts = await this.baseRepository_.serialize(products);
563
- utils_2.eventBuilders.createdProduct({
564
- data: createdProducts,
565
- sharedContext,
566
- });
567
589
  return Array.isArray(data) ? createdProducts : createdProducts[0];
568
590
  }
569
591
  async upsertProducts(data, sharedContext = {}) {
@@ -573,25 +595,13 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
573
595
  let created = [];
574
596
  let updated = [];
575
597
  if (forCreate.length) {
576
- created = await this.createProducts_(forCreate, sharedContext);
598
+ created = await this.createProducts(forCreate, sharedContext);
577
599
  }
578
600
  if (forUpdate.length) {
579
601
  updated = await this.updateProducts_(forUpdate, sharedContext);
580
602
  }
581
603
  const result = [...created, ...updated];
582
604
  const allProducts = await this.baseRepository_.serialize(result);
583
- if (created.length) {
584
- utils_2.eventBuilders.createdProduct({
585
- data: created,
586
- sharedContext,
587
- });
588
- }
589
- if (updated.length) {
590
- utils_2.eventBuilders.updatedProduct({
591
- data: updated,
592
- sharedContext,
593
- });
594
- }
595
605
  return Array.isArray(data) ? allProducts : allProducts[0];
596
606
  }
597
607
  // @ts-expect-error
@@ -611,10 +621,6 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
611
621
  }
612
622
  const products = await this.updateProducts_(normalizedInput, sharedContext);
613
623
  const updatedProducts = await this.baseRepository_.serialize(products);
614
- utils_2.eventBuilders.updatedProduct({
615
- data: updatedProducts,
616
- sharedContext,
617
- });
618
624
  return (0, utils_1.isString)(idOrSelector) ? updatedProducts[0] : updatedProducts;
619
625
  }
620
626
  async createProducts_(data, sharedContext = {}) {
@@ -670,79 +676,34 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
670
676
  return createdProducts;
671
677
  }
672
678
  async updateProducts_(data, sharedContext = {}) {
673
- const normalizedProducts = await this.normalizeUpdateProductInput(data, sharedContext);
679
+ // We have to do that manually because this method is bypassing the product service and goes
680
+ // directly to the custom product repository
681
+ const manager = (sharedContext.transactionManager ??
682
+ sharedContext.manager);
683
+ const subscriber = (0, utils_1.createMedusaMikroOrmEventSubscriber)(["updateProducts_"], this);
684
+ if (manager && subscriber) {
685
+ manager
686
+ .getEventManager()
687
+ .registerSubscriber(new subscriber(sharedContext));
688
+ }
689
+ const originalProducts = await this.productService_.list({
690
+ id: data.map((d) => d.id),
691
+ }, {
692
+ relations: ["options", "options.values", "variants", "images", "tags"],
693
+ }, sharedContext);
694
+ const normalizedProducts = await this.normalizeUpdateProductInput(data, originalProducts);
674
695
  for (const product of normalizedProducts) {
675
696
  this.validateProductUpdatePayload(product);
676
697
  }
677
- const { entities: productData } = await this.productService_.upsertWithReplace(normalizedProducts, {
678
- relations: ["tags", "categories"],
679
- }, sharedContext);
680
- // There is more than 1-level depth of relations here, so we need to handle the options and variants manually
681
- await (0, utils_1.promiseAll)(
682
- // Note: It's safe to rely on the order here as `upsertWithReplace` preserves the order of the input
683
- normalizedProducts.map(async (product, i) => {
684
- const upsertedProduct = productData[i];
685
- let allOptions = [];
686
- if (product.options?.length) {
687
- const { entities: productOptions } = await this.productOptionService_.upsertWithReplace(product.options?.map((option) => ({
688
- ...option,
689
- product_id: upsertedProduct.id,
690
- })) ?? [], { relations: ["values"] }, sharedContext);
691
- upsertedProduct.options = productOptions;
692
- // Since we handle the options and variants outside of the product upsert, we need to clean up manually
693
- await this.productOptionService_.delete({
694
- product_id: upsertedProduct.id,
695
- id: {
696
- $nin: upsertedProduct.options.map(({ id }) => id),
697
- },
698
- }, sharedContext);
699
- allOptions = upsertedProduct.options;
700
- }
701
- else {
702
- // If the options weren't affected, but the user is changing the variants, make sure we have all options available locally
703
- if (product.variants?.length) {
704
- allOptions = await this.productOptionService_.list({ product_id: upsertedProduct.id }, { relations: ["values"] }, sharedContext);
705
- }
706
- }
707
- if (product.variants?.length) {
708
- const productVariantsWithOptions = ProductModuleService.assignOptionsToVariants(product.variants.map((v) => ({
709
- ...v,
710
- product_id: upsertedProduct.id,
711
- })) ?? [], allOptions);
712
- ProductModuleService.checkIfVariantsHaveUniqueOptionsCombinations(productVariantsWithOptions);
713
- const { entities: productVariants } = await this.productVariantService_.upsertWithReplace(productVariantsWithOptions, { relations: ["options"] }, sharedContext);
714
- upsertedProduct.variants = productVariants;
715
- await this.productVariantService_.delete({
716
- product_id: upsertedProduct.id,
717
- id: {
718
- $nin: upsertedProduct.variants.map(({ id }) => id),
719
- },
720
- }, sharedContext);
721
- }
722
- if (Array.isArray(product.images)) {
723
- if (product.images.length) {
724
- const { entities: productImages } = await this.productImageService_.upsertWithReplace(product.images.map((image, rank) => ({
725
- ...image,
726
- product_id: upsertedProduct.id,
727
- rank,
728
- })), {}, sharedContext);
729
- upsertedProduct.images = productImages;
730
- await this.productImageService_.delete({
731
- product_id: upsertedProduct.id,
732
- id: {
733
- $nin: productImages.map(({ id }) => id),
734
- },
735
- }, sharedContext);
736
- }
737
- else {
738
- await this.productImageService_.delete({ product_id: upsertedProduct.id }, sharedContext);
739
- }
740
- }
741
- }));
742
- return productData;
698
+ const updatedProducts = await this.productRepository_.deepUpdate(normalizedProducts, ProductModuleService.validateVariantOptions, sharedContext);
699
+ return updatedProducts;
743
700
  }
744
701
  // @ts-expect-error
745
702
  async updateProductOptionValues(idOrSelector, data, sharedContext = {}) {
703
+ // TODO: There is a missmatch in the API which lead to function with different number of
704
+ // arguments. Therefore, applying the MedusaContext() decorator to the function will not work
705
+ // because the context arg index will differ from method to method.
706
+ sharedContext.messageAggregator ??= new utils_1.MessageAggregator();
746
707
  let normalizedInput = [];
747
708
  if ((0, utils_1.isString)(idOrSelector)) {
748
709
  // This will throw if the product option value does not exist
@@ -756,16 +717,29 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
756
717
  ...data,
757
718
  }));
758
719
  }
759
- const productOptionValues = await super.updateProductOptionValues(normalizedInput, sharedContext);
720
+ const productOptionValues = await this.updateProductOptionValues_(normalizedInput, sharedContext);
760
721
  const updatedProductOptionValues = await this.baseRepository_.serialize(productOptionValues);
761
- utils_2.eventBuilders.updatedProductOptionValue({
762
- data: updatedProductOptionValues,
763
- sharedContext: sharedContext,
764
- });
722
+ // TODO: Because of the wrong method override, we have to compensate to prevent breaking
723
+ // changes right now
724
+ const groupedEvents = sharedContext.messageAggregator.getMessages();
725
+ if (Object.values(groupedEvents).flat().length > 0 &&
726
+ this.eventBusModuleService_) {
727
+ const promises = [];
728
+ for (const group of Object.keys(groupedEvents)) {
729
+ promises.push(this.eventBusModuleService_.emit(groupedEvents[group], {
730
+ internal: true,
731
+ }));
732
+ }
733
+ await Promise.all(promises);
734
+ sharedContext.messageAggregator.clearMessages();
735
+ }
765
736
  return (0, utils_1.isString)(idOrSelector)
766
737
  ? updatedProductOptionValues[0]
767
738
  : updatedProductOptionValues;
768
739
  }
740
+ async updateProductOptionValues_(normalizedInput, sharedContext = {}) {
741
+ return await this.productOptionValueService_.update(normalizedInput, sharedContext);
742
+ }
769
743
  /**
770
744
  * Validates the manually provided handle value of the product
771
745
  * to be URL-safe
@@ -800,7 +774,7 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
800
774
  }
801
775
  async normalizeCreateProductInput(products, sharedContext = {}) {
802
776
  const products_ = Array.isArray(products) ? products : [products];
803
- const normalizedProducts = (await this.normalizeUpdateProductInput(products_, sharedContext));
777
+ const normalizedProducts = (await this.normalizeUpdateProductInput(products_));
804
778
  for (const productData of normalizedProducts) {
805
779
  if (!productData.handle && productData.title) {
806
780
  productData.handle = (0, utils_1.toHandle)(productData.title);
@@ -811,6 +785,20 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
811
785
  if (!productData.thumbnail && productData.images?.length) {
812
786
  productData.thumbnail = productData.images[0].url;
813
787
  }
788
+ // TODO: these props are typed as number, the model expect a string, the API expect number etc
789
+ // There is some inconsistency here, we should fix it
790
+ if ("weight" in productData) {
791
+ productData.weight = productData.weight?.toString();
792
+ }
793
+ if ("length" in productData) {
794
+ productData.length = productData.length?.toString();
795
+ }
796
+ if ("height" in productData) {
797
+ productData.height = productData.height?.toString();
798
+ }
799
+ if ("width" in productData) {
800
+ productData.width = productData.width?.toString();
801
+ }
814
802
  if (productData.images?.length) {
815
803
  productData.images = productData.images.map((image, index) => image.rank != null
816
804
  ? image
@@ -822,12 +810,23 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
822
810
  }
823
811
  return (Array.isArray(products) ? normalizedProducts : normalizedProducts[0]);
824
812
  }
825
- async normalizeUpdateProductInput(products, sharedContext = {}) {
813
+ /**
814
+ * Normalizes the input for the update product input
815
+ * @param products - The products to normalize
816
+ * @param originalProducts - The original products to use for the normalization (must include options and option values relations)
817
+ * @returns The normalized products
818
+ */
819
+ async normalizeUpdateProductInput(products, originalProducts) {
826
820
  const products_ = Array.isArray(products) ? products : [products];
827
821
  const productsIds = products_.map((p) => p.id).filter(Boolean);
828
822
  let dbOptions = [];
829
823
  if (productsIds.length) {
830
- dbOptions = await this.productOptionService_.list({ product_id: productsIds }, { relations: ["values"] }, sharedContext);
824
+ // Re map options to handle non serialized data as well
825
+ dbOptions =
826
+ originalProducts
827
+ ?.map((originalProduct) => originalProduct.options.map((option) => option))
828
+ .flat()
829
+ .filter(Boolean) ?? [];
831
830
  }
832
831
  const normalizedProducts = [];
833
832
  for (const product of products_) {
@@ -838,7 +837,8 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
838
837
  if (productData.options?.length) {
839
838
  ;
840
839
  productData.options = productData.options?.map((option) => {
841
- const dbOption = dbOptions.find((o) => o.title === option.title && o.product_id === productData.id);
840
+ const dbOption = dbOptions.find((o) => (o.title === option.title || o.id === option.id) &&
841
+ o.product_id === productData.id);
842
842
  return {
843
843
  title: option.title,
844
844
  values: option.values?.map((value) => {
@@ -886,6 +886,14 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
886
886
  }
887
887
  return collectionData;
888
888
  }
889
+ static validateVariantOptions(variants, options) {
890
+ const variantsWithOptions = ProductModuleService.assignOptionsToVariants(variants.map((v) => ({
891
+ ...v,
892
+ // adding product_id to the variant to make it valid for the assignOptionsToVariants function
893
+ ...(options.length ? { product_id: options[0].product_id } : {}),
894
+ })), options);
895
+ ProductModuleService.checkIfVariantsHaveUniqueOptionsCombinations(variantsWithOptions);
896
+ }
889
897
  static assignOptionsToVariants(variants, options) {
890
898
  if (!variants.length) {
891
899
  return variants;
@@ -895,7 +903,7 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
895
903
  const productsOptions = options.filter((o) => o.product_id === variant.product_id);
896
904
  if (numOfProvidedVariantOptionValues &&
897
905
  productsOptions.length !== numOfProvidedVariantOptionValues) {
898
- throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Product has ${productsOptions.length} but there were ${numOfProvidedVariantOptionValues} provided option values for the variant: ${variant.title}.`);
906
+ throw new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, `Product has ${productsOptions.length} option values but there were ${numOfProvidedVariantOptionValues} provided option values for the variant: ${variant.title}.`);
899
907
  }
900
908
  const variantOptions = Object.entries(variant.options || {}).map(([key, val]) => {
901
909
  const option = productsOptions.find((o) => o.title === key);
@@ -961,6 +969,169 @@ class ProductModuleService extends (0, utils_1.MedusaService)({
961
969
  }
962
970
  }
963
971
  }
972
+ // @ts-ignore
973
+ async listProductVariants(filters, config, sharedContext = {}) {
974
+ const shouldLoadImages = config?.relations?.includes("images");
975
+ const relations = [...(config?.relations || [])];
976
+ if (shouldLoadImages) {
977
+ relations.push("product.images");
978
+ }
979
+ const variants = await this.productVariantService_.list(filters, {
980
+ ...config,
981
+ relations,
982
+ }, sharedContext);
983
+ if (shouldLoadImages) {
984
+ // Get variant images for all variants
985
+ const variantImagesMap = await this.getVariantImages(variants, sharedContext);
986
+ for (const variant of variants) {
987
+ variant.images = variantImagesMap.get(variant.id) || [];
988
+ }
989
+ }
990
+ return this.baseRepository_.serialize(variants);
991
+ }
992
+ // @ts-ignore
993
+ async listAndCountProductVariants(filters, config, sharedContext = {}) {
994
+ const shouldLoadImages = config?.relations?.includes("images");
995
+ const relations = [...(config?.relations || [])];
996
+ if (shouldLoadImages) {
997
+ relations.push("product.images");
998
+ }
999
+ const [variants, count] = await this.productVariantService_.listAndCount(filters, {
1000
+ ...config,
1001
+ relations,
1002
+ }, sharedContext);
1003
+ if (shouldLoadImages) {
1004
+ // Get variant images for all variants
1005
+ const variantImagesMap = await this.getVariantImages(variants, sharedContext);
1006
+ for (const variant of variants) {
1007
+ variant.images = variantImagesMap.get(variant.id) || [];
1008
+ }
1009
+ }
1010
+ const serializedVariants = await this.baseRepository_.serialize(variants);
1011
+ return [serializedVariants, count];
1012
+ }
1013
+ // @ts-ignore
1014
+ async retrieveProductVariant(id, config, sharedContext = {}) {
1015
+ const shouldLoadImages = config?.relations?.includes("images");
1016
+ const relations = [...(config?.relations || [])];
1017
+ if (shouldLoadImages) {
1018
+ relations.push("images", "product", "product.images");
1019
+ }
1020
+ const variant = await this.productVariantService_.retrieve(id, {
1021
+ ...config,
1022
+ relations,
1023
+ }, sharedContext);
1024
+ if (shouldLoadImages) {
1025
+ const variantImages = await this.getVariantImages([variant], sharedContext);
1026
+ variant.images = variantImages.get(id) || [];
1027
+ }
1028
+ return this.baseRepository_.serialize(variant);
1029
+ }
1030
+ async addImageToVariant(data, sharedContext = {}) {
1031
+ const productVariantProductImage = await this.addImageToVariant_(data, sharedContext);
1032
+ return productVariantProductImage;
1033
+ }
1034
+ async addImageToVariant_(data, sharedContext = {}) {
1035
+ // TODO: consider validation that image and variant are on the same product
1036
+ const productVariantProductImage = await this.productVariantProductImageService_.create(data, sharedContext);
1037
+ return productVariantProductImage.map((vi) => ({ id: vi.id }));
1038
+ }
1039
+ async removeImageFromVariant(data, sharedContext = {}) {
1040
+ await this.removeImageFromVariant_(data, sharedContext);
1041
+ }
1042
+ async removeImageFromVariant_(data, sharedContext = {}) {
1043
+ const pairs = Array.isArray(data) ? data : [data];
1044
+ const productVariantProductImages = await this.productVariantProductImageService_.list({
1045
+ $or: pairs,
1046
+ });
1047
+ await this.productVariantProductImageService_.delete(productVariantProductImages.map((p) => p.id), sharedContext);
1048
+ }
1049
+ async getVariantImages(variants, context = {}) {
1050
+ if (variants.length === 0) {
1051
+ return new Map();
1052
+ }
1053
+ // Create lookup maps for efficient processing
1054
+ const uniqueProductIds = new Set();
1055
+ // Build lookup maps
1056
+ for (const variant of variants) {
1057
+ if (variant.product_id) {
1058
+ uniqueProductIds.add(variant.product_id);
1059
+ }
1060
+ }
1061
+ const allProductImages = (await this.listProductImages({ product_id: Array.from(uniqueProductIds) }, {
1062
+ relations: ["variants"],
1063
+ }, context));
1064
+ // all product images
1065
+ const imagesByProductId = new Map();
1066
+ // variant specific images
1067
+ const variantSpecificImageIds = new Map();
1068
+ // Single pass to build both lookup maps
1069
+ for (const img of allProductImages) {
1070
+ // Group by product_id
1071
+ if (!imagesByProductId.has(img.product_id)) {
1072
+ imagesByProductId.set(img.product_id, []);
1073
+ }
1074
+ imagesByProductId.get(img.product_id).push(img);
1075
+ // Track variant-specific images
1076
+ if (img.variants.length > 0) {
1077
+ for (const variant of img.variants) {
1078
+ if (!variantSpecificImageIds.has(variant.id)) {
1079
+ variantSpecificImageIds.set(variant.id, new Set());
1080
+ }
1081
+ variantSpecificImageIds.get(variant.id).add(img.id || "");
1082
+ }
1083
+ }
1084
+ }
1085
+ const result = new Map();
1086
+ for (const variant of variants) {
1087
+ const productId = variant.product_id;
1088
+ const productImages = imagesByProductId.get(productId) || [];
1089
+ const specificImageIds = variantSpecificImageIds.get(variant.id) || new Set();
1090
+ const variantImages = productImages.filter((img) => {
1091
+ // general product image
1092
+ if (!img.variants.length) {
1093
+ return true;
1094
+ }
1095
+ // Check if this image is specifically associated with this variant
1096
+ return specificImageIds.has(img.id || "");
1097
+ });
1098
+ result.set(variant.id, variantImages);
1099
+ }
1100
+ return result;
1101
+ }
1102
+ async buildVariantImagesFromProduct(variants, productImages, sharedContext = {}) {
1103
+ // Create a clean map of images without problematic collections
1104
+ const imagesMap = new Map();
1105
+ for (const img of productImages) {
1106
+ imagesMap.set(img.id, img);
1107
+ }
1108
+ const variantIds = variants.map((v) => v.id);
1109
+ const variantImageRelations = await this.productVariantProductImageService_.list({ variant_id: variantIds }, { select: ["variant_id", "image_id"] }, sharedContext);
1110
+ const variantIdImageIdsMap = new Map();
1111
+ const imageIdVariantIdsMap = new Map();
1112
+ // build both lookup
1113
+ for (const relation of variantImageRelations) {
1114
+ if (!variantIdImageIdsMap.has(relation.variant_id)) {
1115
+ variantIdImageIdsMap.set(relation.variant_id, []);
1116
+ }
1117
+ variantIdImageIdsMap.get(relation.variant_id).push(relation.image_id);
1118
+ if (!imageIdVariantIdsMap.has(relation.image_id)) {
1119
+ imageIdVariantIdsMap.set(relation.image_id, []);
1120
+ }
1121
+ imageIdVariantIdsMap.get(relation.image_id).push(relation.variant_id);
1122
+ }
1123
+ const [generalImages, variantImages] = (0, utils_1.partitionArray)(productImages, (img) => !imageIdVariantIdsMap.has(img.id) // if image doesn't have any variants, it is a general image
1124
+ );
1125
+ for (const variant of variants) {
1126
+ const variantImageIds = variantIdImageIdsMap.get(variant.id) || [];
1127
+ variant.images = [...generalImages];
1128
+ for (const image of variantImages) {
1129
+ if (variantImageIds.includes(image.id)) {
1130
+ variant.images.push(image);
1131
+ }
1132
+ }
1133
+ }
1134
+ }
964
1135
  }
965
1136
  exports.default = ProductModuleService;
966
1137
  __decorate([
@@ -1041,13 +1212,20 @@ __decorate([
1041
1212
  __metadata("design:returntype", Promise)
1042
1213
  ], ProductModuleService.prototype, "createProductTags", null);
1043
1214
  __decorate([
1044
- (0, utils_1.InjectTransactionManager)(),
1215
+ (0, utils_1.InjectManager)(),
1045
1216
  (0, utils_1.EmitEvents)(),
1046
1217
  __param(1, (0, utils_1.MedusaContext)()),
1047
1218
  __metadata("design:type", Function),
1048
1219
  __metadata("design:paramtypes", [Object, Object]),
1049
1220
  __metadata("design:returntype", Promise)
1050
1221
  ], ProductModuleService.prototype, "upsertProductTags", null);
1222
+ __decorate([
1223
+ (0, utils_1.InjectTransactionManager)(),
1224
+ __param(1, (0, utils_1.MedusaContext)()),
1225
+ __metadata("design:type", Function),
1226
+ __metadata("design:paramtypes", [Object, Object]),
1227
+ __metadata("design:returntype", Promise)
1228
+ ], ProductModuleService.prototype, "upsertProductTags_", null);
1051
1229
  __decorate([
1052
1230
  (0, utils_1.InjectManager)(),
1053
1231
  (0, utils_1.EmitEvents)()
@@ -1059,7 +1237,8 @@ __decorate([
1059
1237
  __metadata("design:returntype", Promise)
1060
1238
  ], ProductModuleService.prototype, "updateProductTags", null);
1061
1239
  __decorate([
1062
- (0, utils_1.InjectManager)()
1240
+ (0, utils_1.InjectManager)(),
1241
+ (0, utils_1.EmitEvents)()
1063
1242
  // @ts-expect-error
1064
1243
  ,
1065
1244
  __param(1, (0, utils_1.MedusaContext)()),
@@ -1068,14 +1247,22 @@ __decorate([
1068
1247
  __metadata("design:returntype", Promise)
1069
1248
  ], ProductModuleService.prototype, "createProductTypes", null);
1070
1249
  __decorate([
1071
- (0, utils_1.InjectTransactionManager)(),
1250
+ (0, utils_1.InjectManager)(),
1251
+ (0, utils_1.EmitEvents)(),
1072
1252
  __param(1, (0, utils_1.MedusaContext)()),
1073
1253
  __metadata("design:type", Function),
1074
1254
  __metadata("design:paramtypes", [Object, Object]),
1075
1255
  __metadata("design:returntype", Promise)
1076
1256
  ], ProductModuleService.prototype, "upsertProductTypes", null);
1077
1257
  __decorate([
1078
- (0, utils_1.InjectManager)()
1258
+ (0, utils_1.InjectTransactionManager)(),
1259
+ __metadata("design:type", Function),
1260
+ __metadata("design:paramtypes", [Object, Object]),
1261
+ __metadata("design:returntype", Promise)
1262
+ ], ProductModuleService.prototype, "upsertProductTypes_", null);
1263
+ __decorate([
1264
+ (0, utils_1.InjectManager)(),
1265
+ (0, utils_1.EmitEvents)()
1079
1266
  // @ts-expect-error
1080
1267
  ,
1081
1268
  __param(2, (0, utils_1.MedusaContext)()),
@@ -1084,7 +1271,8 @@ __decorate([
1084
1271
  __metadata("design:returntype", Promise)
1085
1272
  ], ProductModuleService.prototype, "updateProductTypes", null);
1086
1273
  __decorate([
1087
- (0, utils_1.InjectManager)()
1274
+ (0, utils_1.InjectManager)(),
1275
+ (0, utils_1.EmitEvents)()
1088
1276
  // @ts-expect-error
1089
1277
  ,
1090
1278
  __param(1, (0, utils_1.MedusaContext)()),
@@ -1101,13 +1289,15 @@ __decorate([
1101
1289
  ], ProductModuleService.prototype, "createOptions_", null);
1102
1290
  __decorate([
1103
1291
  (0, utils_1.InjectTransactionManager)(),
1292
+ (0, utils_1.EmitEvents)(),
1104
1293
  __param(1, (0, utils_1.MedusaContext)()),
1105
1294
  __metadata("design:type", Function),
1106
1295
  __metadata("design:paramtypes", [Object, Object]),
1107
1296
  __metadata("design:returntype", Promise)
1108
1297
  ], ProductModuleService.prototype, "upsertProductOptions", null);
1109
1298
  __decorate([
1110
- (0, utils_1.InjectManager)()
1299
+ (0, utils_1.InjectManager)(),
1300
+ (0, utils_1.EmitEvents)()
1111
1301
  // @ts-expect-error
1112
1302
  ,
1113
1303
  __param(2, (0, utils_1.MedusaContext)()),
@@ -1140,13 +1330,20 @@ __decorate([
1140
1330
  __metadata("design:returntype", Promise)
1141
1331
  ], ProductModuleService.prototype, "createCollections_", null);
1142
1332
  __decorate([
1143
- (0, utils_1.InjectTransactionManager)(),
1333
+ (0, utils_1.InjectManager)(),
1144
1334
  (0, utils_1.EmitEvents)(),
1145
1335
  __param(1, (0, utils_1.MedusaContext)()),
1146
1336
  __metadata("design:type", Function),
1147
1337
  __metadata("design:paramtypes", [Object, Object]),
1148
1338
  __metadata("design:returntype", Promise)
1149
1339
  ], ProductModuleService.prototype, "upsertProductCollections", null);
1340
+ __decorate([
1341
+ (0, utils_1.InjectTransactionManager)(),
1342
+ __param(1, (0, utils_1.MedusaContext)()),
1343
+ __metadata("design:type", Function),
1344
+ __metadata("design:paramtypes", [Object, Object]),
1345
+ __metadata("design:returntype", Promise)
1346
+ ], ProductModuleService.prototype, "upsertCollections_", null);
1150
1347
  __decorate([
1151
1348
  (0, utils_1.InjectManager)(),
1152
1349
  (0, utils_1.EmitEvents)()
@@ -1175,13 +1372,20 @@ __decorate([
1175
1372
  __metadata("design:returntype", Promise)
1176
1373
  ], ProductModuleService.prototype, "createProductCategories", null);
1177
1374
  __decorate([
1178
- (0, utils_1.InjectTransactionManager)(),
1375
+ (0, utils_1.InjectManager)(),
1179
1376
  (0, utils_1.EmitEvents)(),
1180
1377
  __param(1, (0, utils_1.MedusaContext)()),
1181
1378
  __metadata("design:type", Function),
1182
1379
  __metadata("design:paramtypes", [Object, Object]),
1183
1380
  __metadata("design:returntype", Promise)
1184
1381
  ], ProductModuleService.prototype, "upsertProductCategories", null);
1382
+ __decorate([
1383
+ (0, utils_1.InjectTransactionManager)(),
1384
+ __param(1, (0, utils_1.MedusaContext)()),
1385
+ __metadata("design:type", Function),
1386
+ __metadata("design:paramtypes", [Object, Object]),
1387
+ __metadata("design:returntype", Promise)
1388
+ ], ProductModuleService.prototype, "upsertProductCategories_", null);
1185
1389
  __decorate([
1186
1390
  (0, utils_1.InjectManager)(),
1187
1391
  (0, utils_1.EmitEvents)()
@@ -1192,6 +1396,13 @@ __decorate([
1192
1396
  __metadata("design:paramtypes", [Object, Object, Object]),
1193
1397
  __metadata("design:returntype", Promise)
1194
1398
  ], ProductModuleService.prototype, "updateProductCategories", null);
1399
+ __decorate([
1400
+ (0, utils_1.InjectTransactionManager)(),
1401
+ __param(2, (0, utils_1.MedusaContext)()),
1402
+ __metadata("design:type", Function),
1403
+ __metadata("design:paramtypes", [Object, Object, Object]),
1404
+ __metadata("design:returntype", Promise)
1405
+ ], ProductModuleService.prototype, "updateProductCategories_", null);
1195
1406
  __decorate([
1196
1407
  (0, utils_1.InjectManager)(),
1197
1408
  (0, utils_1.EmitEvents)()
@@ -1234,6 +1445,23 @@ __decorate([
1234
1445
  __metadata("design:paramtypes", [Array, Object]),
1235
1446
  __metadata("design:returntype", Promise)
1236
1447
  ], ProductModuleService.prototype, "updateProducts_", null);
1448
+ __decorate([
1449
+ (0, utils_1.InjectManager)(),
1450
+ (0, utils_1.EmitEvents)()
1451
+ // @ts-expect-error
1452
+ ,
1453
+ __param(2, (0, utils_1.MedusaContext)()),
1454
+ __metadata("design:type", Function),
1455
+ __metadata("design:paramtypes", [Object, Object, Object]),
1456
+ __metadata("design:returntype", Promise)
1457
+ ], ProductModuleService.prototype, "updateProductOptionValues", null);
1458
+ __decorate([
1459
+ (0, utils_1.InjectTransactionManager)(),
1460
+ __param(1, (0, utils_1.MedusaContext)()),
1461
+ __metadata("design:type", Function),
1462
+ __metadata("design:paramtypes", [Array, Object]),
1463
+ __metadata("design:returntype", Promise)
1464
+ ], ProductModuleService.prototype, "updateProductOptionValues_", null);
1237
1465
  __decorate([
1238
1466
  __param(1, (0, utils_1.MedusaContext)()),
1239
1467
  __metadata("design:type", Function),
@@ -1241,9 +1469,64 @@ __decorate([
1241
1469
  __metadata("design:returntype", Promise)
1242
1470
  ], ProductModuleService.prototype, "normalizeCreateProductInput", null);
1243
1471
  __decorate([
1472
+ (0, utils_1.InjectManager)()
1473
+ // @ts-ignore
1474
+ ,
1475
+ __param(2, (0, utils_1.MedusaContext)()),
1476
+ __metadata("design:type", Function),
1477
+ __metadata("design:paramtypes", [Object, Object, Object]),
1478
+ __metadata("design:returntype", Promise)
1479
+ ], ProductModuleService.prototype, "listProductVariants", null);
1480
+ __decorate([
1481
+ (0, utils_1.InjectManager)()
1482
+ // @ts-ignore
1483
+ ,
1484
+ __param(2, (0, utils_1.MedusaContext)()),
1485
+ __metadata("design:type", Function),
1486
+ __metadata("design:paramtypes", [Object, Object, Object]),
1487
+ __metadata("design:returntype", Promise)
1488
+ ], ProductModuleService.prototype, "listAndCountProductVariants", null);
1489
+ __decorate([
1490
+ (0, utils_1.InjectManager)()
1491
+ // @ts-ignore
1492
+ ,
1493
+ __param(2, (0, utils_1.MedusaContext)()),
1494
+ __metadata("design:type", Function),
1495
+ __metadata("design:paramtypes", [String, Object, Object]),
1496
+ __metadata("design:returntype", Promise)
1497
+ ], ProductModuleService.prototype, "retrieveProductVariant", null);
1498
+ __decorate([
1499
+ (0, utils_1.InjectManager)(),
1244
1500
  __param(1, (0, utils_1.MedusaContext)()),
1245
1501
  __metadata("design:type", Function),
1246
- __metadata("design:paramtypes", [typeof (_b = typeof T !== "undefined" && T) === "function" ? _b : Object, Object]),
1502
+ __metadata("design:paramtypes", [Array, Object]),
1503
+ __metadata("design:returntype", Promise)
1504
+ ], ProductModuleService.prototype, "addImageToVariant", null);
1505
+ __decorate([
1506
+ (0, utils_1.InjectTransactionManager)(),
1507
+ __param(1, (0, utils_1.MedusaContext)()),
1508
+ __metadata("design:type", Function),
1509
+ __metadata("design:paramtypes", [Array, Object]),
1510
+ __metadata("design:returntype", Promise)
1511
+ ], ProductModuleService.prototype, "addImageToVariant_", null);
1512
+ __decorate([
1513
+ (0, utils_1.InjectManager)(),
1514
+ __param(1, (0, utils_1.MedusaContext)()),
1515
+ __metadata("design:type", Function),
1516
+ __metadata("design:paramtypes", [Array, Object]),
1517
+ __metadata("design:returntype", Promise)
1518
+ ], ProductModuleService.prototype, "removeImageFromVariant", null);
1519
+ __decorate([
1520
+ (0, utils_1.InjectTransactionManager)(),
1521
+ __param(1, (0, utils_1.MedusaContext)()),
1522
+ __metadata("design:type", Function),
1523
+ __metadata("design:paramtypes", [Array, Object]),
1524
+ __metadata("design:returntype", Promise)
1525
+ ], ProductModuleService.prototype, "removeImageFromVariant_", null);
1526
+ __decorate([
1527
+ (0, utils_1.InjectManager)(),
1528
+ __metadata("design:type", Function),
1529
+ __metadata("design:paramtypes", [Array, Object]),
1247
1530
  __metadata("design:returntype", Promise)
1248
- ], ProductModuleService.prototype, "normalizeUpdateProductInput", null);
1531
+ ], ProductModuleService.prototype, "getVariantImages", null);
1249
1532
  //# sourceMappingURL=product-module-service.js.map