@labdigital/commercetools-mock 2.2.0 → 2.4.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/dist/index.cjs +366 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +366 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/repositories/category.ts +26 -0
- package/src/repositories/product.ts +484 -20
- package/src/services/category.test.ts +99 -0
- package/src/services/product.test.ts +898 -7
package/package.json
CHANGED
|
@@ -4,6 +4,8 @@ import type {
|
|
|
4
4
|
Category,
|
|
5
5
|
CategoryAddAssetAction,
|
|
6
6
|
CategoryChangeAssetNameAction,
|
|
7
|
+
CategoryChangeNameAction,
|
|
8
|
+
CategoryChangeParentAction,
|
|
7
9
|
CategoryChangeSlugAction,
|
|
8
10
|
CategoryDraft,
|
|
9
11
|
CategoryRemoveAssetAction,
|
|
@@ -98,6 +100,30 @@ export class CategoryRepository extends AbstractResourceRepository<'category'> {
|
|
|
98
100
|
) => {
|
|
99
101
|
resource.slug = slug
|
|
100
102
|
},
|
|
103
|
+
changeName: (
|
|
104
|
+
context: RepositoryContext,
|
|
105
|
+
resource: Writable<Category>,
|
|
106
|
+
{ name }: CategoryChangeNameAction
|
|
107
|
+
) => {
|
|
108
|
+
resource.name = name
|
|
109
|
+
},
|
|
110
|
+
changeParent: (
|
|
111
|
+
context: RepositoryContext,
|
|
112
|
+
resource: Writable<Category>,
|
|
113
|
+
{ parent }: CategoryChangeParentAction
|
|
114
|
+
) => {
|
|
115
|
+
const category = this._storage.getByResourceIdentifier(
|
|
116
|
+
context.projectKey,
|
|
117
|
+
parent
|
|
118
|
+
)
|
|
119
|
+
if (!category) {
|
|
120
|
+
throw new Error('No category found for reference')
|
|
121
|
+
}
|
|
122
|
+
resource.parent = {
|
|
123
|
+
typeId: 'category',
|
|
124
|
+
id: category.id,
|
|
125
|
+
}
|
|
126
|
+
},
|
|
101
127
|
setKey: (
|
|
102
128
|
context: RepositoryContext,
|
|
103
129
|
resource: Writable<Category>,
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
ProductDraft,
|
|
7
7
|
ProductPublishAction,
|
|
8
8
|
ProductSetAttributeAction,
|
|
9
|
+
ProductSetAttributeInAllVariantsAction,
|
|
9
10
|
ProductSetDescriptionAction,
|
|
10
11
|
ProductAddExternalImageAction,
|
|
11
12
|
ProductRemoveImageAction,
|
|
@@ -18,6 +19,23 @@ import type {
|
|
|
18
19
|
ProductChangePriceAction,
|
|
19
20
|
ProductAddPriceAction,
|
|
20
21
|
ProductRemovePriceAction,
|
|
22
|
+
CategoryReference,
|
|
23
|
+
InvalidJsonInputError,
|
|
24
|
+
InvalidOperationError,
|
|
25
|
+
TaxCategoryReference,
|
|
26
|
+
StateReference,
|
|
27
|
+
ProductChangeNameAction,
|
|
28
|
+
ProductChangeSlugAction,
|
|
29
|
+
ProductSetMetaTitleAction,
|
|
30
|
+
ProductSetMetaDescriptionAction,
|
|
31
|
+
ProductSetMetaKeywordsAction,
|
|
32
|
+
ProductAddVariantAction,
|
|
33
|
+
ProductRemoveVariantAction,
|
|
34
|
+
ProductChangeMasterVariantAction,
|
|
35
|
+
ProductSetTaxCategoryAction,
|
|
36
|
+
ProductAddToCategoryAction,
|
|
37
|
+
ProductRemoveFromCategoryAction,
|
|
38
|
+
ProductTransitionStateAction,
|
|
21
39
|
} from '@commercetools/platform-sdk'
|
|
22
40
|
import { v4 as uuidv4 } from 'uuid'
|
|
23
41
|
import type { Writable } from '../types.js'
|
|
@@ -28,6 +46,7 @@ import {
|
|
|
28
46
|
getReferenceFromResourceIdentifier,
|
|
29
47
|
} from './helpers.js'
|
|
30
48
|
import deepEqual from 'deep-equal'
|
|
49
|
+
import { CommercetoolsError } from '../exceptions.js'
|
|
31
50
|
|
|
32
51
|
export class ProductRepository extends AbstractResourceRepository<'product'> {
|
|
33
52
|
getTypeId() {
|
|
@@ -57,16 +76,64 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
|
|
|
57
76
|
}
|
|
58
77
|
}
|
|
59
78
|
|
|
79
|
+
// Resolve Product categories
|
|
80
|
+
const categoryReferences: CategoryReference[] = []
|
|
81
|
+
draft.categories?.forEach((category) => {
|
|
82
|
+
if (category) {
|
|
83
|
+
categoryReferences.push(
|
|
84
|
+
getReferenceFromResourceIdentifier<CategoryReference>(
|
|
85
|
+
category,
|
|
86
|
+
context.projectKey,
|
|
87
|
+
this._storage
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
} else {
|
|
91
|
+
throw new CommercetoolsError<InvalidJsonInputError>(
|
|
92
|
+
{
|
|
93
|
+
code: 'InvalidJsonInput',
|
|
94
|
+
message: 'Request body does not contain valid JSON.',
|
|
95
|
+
detailedErrorMessage: 'categories: JSON object expected.',
|
|
96
|
+
},
|
|
97
|
+
400
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// Resolve Tax category
|
|
103
|
+
let taxCategoryReference: TaxCategoryReference | undefined = undefined
|
|
104
|
+
if (draft.taxCategory) {
|
|
105
|
+
taxCategoryReference =
|
|
106
|
+
getReferenceFromResourceIdentifier<TaxCategoryReference>(
|
|
107
|
+
draft.taxCategory,
|
|
108
|
+
context.projectKey,
|
|
109
|
+
this._storage
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Resolve Product State
|
|
114
|
+
let productStateReference: StateReference | undefined = undefined
|
|
115
|
+
if (draft.state) {
|
|
116
|
+
productStateReference =
|
|
117
|
+
getReferenceFromResourceIdentifier<StateReference>(
|
|
118
|
+
draft.state,
|
|
119
|
+
context.projectKey,
|
|
120
|
+
this._storage
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
60
124
|
const productData: ProductData = {
|
|
61
125
|
name: draft.name,
|
|
62
126
|
slug: draft.slug,
|
|
63
|
-
|
|
127
|
+
description: draft.description,
|
|
128
|
+
categories: categoryReferences,
|
|
64
129
|
masterVariant: variantFromDraft(1, draft.masterVariant),
|
|
65
130
|
variants:
|
|
66
131
|
draft.variants?.map((variant, index) =>
|
|
67
132
|
variantFromDraft(index + 2, variant)
|
|
68
133
|
) ?? [],
|
|
69
|
-
|
|
134
|
+
metaTitle: draft.metaTitle,
|
|
135
|
+
metaDescription: draft.metaDescription,
|
|
136
|
+
metaKeywords: draft.metaKeywords,
|
|
70
137
|
searchKeywords: draft.searchKeywords ?? {},
|
|
71
138
|
}
|
|
72
139
|
|
|
@@ -74,6 +141,8 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
|
|
|
74
141
|
...getBaseResourceProperties(),
|
|
75
142
|
key: draft.key,
|
|
76
143
|
productType: productType,
|
|
144
|
+
taxCategory: taxCategoryReference,
|
|
145
|
+
state: productStateReference,
|
|
77
146
|
masterData: {
|
|
78
147
|
current: productData,
|
|
79
148
|
staged: productData,
|
|
@@ -170,6 +239,65 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
|
|
|
170
239
|
|
|
171
240
|
return resource
|
|
172
241
|
},
|
|
242
|
+
setAttributeInAllVariants: (
|
|
243
|
+
context: RepositoryContext,
|
|
244
|
+
resource: Writable<Product>,
|
|
245
|
+
{ name, value, staged }: ProductSetAttributeInAllVariantsAction
|
|
246
|
+
) => {
|
|
247
|
+
const setAttrInAllVariants = (data: Writable<ProductData>) => {
|
|
248
|
+
if (!data.masterVariant.attributes) {
|
|
249
|
+
data.masterVariant.attributes = []
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const existingAttr = data.masterVariant.attributes?.find(
|
|
253
|
+
(attr) => attr.name === name
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
if (existingAttr) {
|
|
257
|
+
existingAttr.value = value
|
|
258
|
+
} else {
|
|
259
|
+
data.masterVariant.attributes.push({
|
|
260
|
+
name,
|
|
261
|
+
value,
|
|
262
|
+
})
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
data.variants.forEach((variant) => {
|
|
266
|
+
if (!variant.attributes) {
|
|
267
|
+
variant.attributes = []
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const existingAttr = variant.attributes.find(
|
|
271
|
+
(attr) => attr.name === name
|
|
272
|
+
)
|
|
273
|
+
if (existingAttr) {
|
|
274
|
+
existingAttr.value = value
|
|
275
|
+
} else {
|
|
276
|
+
variant.attributes.push({
|
|
277
|
+
name,
|
|
278
|
+
value,
|
|
279
|
+
})
|
|
280
|
+
}
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// If true, only the staged Attribute is set. If false, both current and
|
|
285
|
+
// staged Attribute is set. Default is true
|
|
286
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
287
|
+
|
|
288
|
+
// Write the attribute to the staged data
|
|
289
|
+
setAttrInAllVariants(resource.masterData.staged)
|
|
290
|
+
|
|
291
|
+
// Also write to published data is isStaged = false
|
|
292
|
+
// if isStaged is false we set the attribute on both the staged and
|
|
293
|
+
// published data.
|
|
294
|
+
if (!onlyStaged) {
|
|
295
|
+
setAttrInAllVariants(resource.masterData.current)
|
|
296
|
+
}
|
|
297
|
+
checkForStagedChanges(resource)
|
|
298
|
+
|
|
299
|
+
return resource
|
|
300
|
+
},
|
|
173
301
|
setDescription: (
|
|
174
302
|
context: RepositoryContext,
|
|
175
303
|
resource: Writable<Product>,
|
|
@@ -366,13 +494,15 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
|
|
|
366
494
|
|
|
367
495
|
return resource
|
|
368
496
|
},
|
|
369
|
-
|
|
370
497
|
addPrice: (
|
|
371
498
|
context: RepositoryContext,
|
|
372
499
|
resource: Writable<Product>,
|
|
373
500
|
{ variantId, sku, price, staged }: ProductAddPriceAction
|
|
374
501
|
) => {
|
|
375
|
-
const addVariantPrice = (
|
|
502
|
+
const addVariantPrice = (
|
|
503
|
+
data: Writable<ProductData>,
|
|
504
|
+
priceToAdd: Price
|
|
505
|
+
) => {
|
|
376
506
|
const { variant, isMasterVariant, variantIndex } = getVariant(
|
|
377
507
|
data,
|
|
378
508
|
variantId,
|
|
@@ -385,9 +515,9 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
|
|
|
385
515
|
}
|
|
386
516
|
|
|
387
517
|
if (variant.prices === undefined) {
|
|
388
|
-
variant.prices = [
|
|
518
|
+
variant.prices = [priceToAdd]
|
|
389
519
|
} else {
|
|
390
|
-
variant.prices.push(
|
|
520
|
+
variant.prices.push(priceToAdd)
|
|
391
521
|
}
|
|
392
522
|
|
|
393
523
|
if (isMasterVariant) {
|
|
@@ -397,18 +527,21 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
|
|
|
397
527
|
}
|
|
398
528
|
}
|
|
399
529
|
|
|
530
|
+
// Pre-creating the price object ensures consistency between staged and current versions
|
|
531
|
+
const priceToAdd = priceFromDraft(price)
|
|
532
|
+
|
|
400
533
|
// If true, only the staged Attribute is set. If false, both current and
|
|
401
534
|
// staged Attribute is set. Default is true
|
|
402
535
|
const onlyStaged = staged !== undefined ? staged : true
|
|
403
536
|
|
|
404
537
|
// Write the attribute to the staged data
|
|
405
|
-
addVariantPrice(resource.masterData.staged)
|
|
538
|
+
addVariantPrice(resource.masterData.staged, priceToAdd)
|
|
406
539
|
|
|
407
540
|
// Also write to published data is isStaged = false
|
|
408
541
|
// if isStaged is false we set the attribute on both the staged and
|
|
409
542
|
// published data.
|
|
410
543
|
if (!onlyStaged) {
|
|
411
|
-
addVariantPrice(resource.masterData.current)
|
|
544
|
+
addVariantPrice(resource.masterData.current, priceToAdd)
|
|
412
545
|
}
|
|
413
546
|
checkForStagedChanges(resource)
|
|
414
547
|
|
|
@@ -525,21 +658,354 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
|
|
|
525
658
|
|
|
526
659
|
return resource
|
|
527
660
|
},
|
|
661
|
+
changeName: (
|
|
662
|
+
context: RepositoryContext,
|
|
663
|
+
resource: Writable<Product>,
|
|
664
|
+
{ name, staged }: ProductChangeNameAction
|
|
665
|
+
) => {
|
|
666
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
667
|
+
resource.masterData.staged.name = name
|
|
668
|
+
if (!onlyStaged) {
|
|
669
|
+
resource.masterData.current.name = name
|
|
670
|
+
}
|
|
671
|
+
checkForStagedChanges(resource)
|
|
672
|
+
return resource
|
|
673
|
+
},
|
|
674
|
+
changeSlug: (
|
|
675
|
+
context: RepositoryContext,
|
|
676
|
+
resource: Writable<Product>,
|
|
677
|
+
{ slug, staged }: ProductChangeSlugAction
|
|
678
|
+
) => {
|
|
679
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
680
|
+
resource.masterData.staged.slug = slug
|
|
681
|
+
if (!onlyStaged) {
|
|
682
|
+
resource.masterData.current.slug = slug
|
|
683
|
+
}
|
|
684
|
+
checkForStagedChanges(resource)
|
|
685
|
+
return resource
|
|
686
|
+
},
|
|
687
|
+
setMetaTitle: (
|
|
688
|
+
context: RepositoryContext,
|
|
689
|
+
resource: Writable<Product>,
|
|
690
|
+
{ metaTitle, staged }: ProductSetMetaTitleAction
|
|
691
|
+
) => {
|
|
692
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
693
|
+
resource.masterData.staged.metaTitle = metaTitle
|
|
694
|
+
if (!onlyStaged) {
|
|
695
|
+
resource.masterData.current.metaTitle = metaTitle
|
|
696
|
+
}
|
|
697
|
+
checkForStagedChanges(resource)
|
|
698
|
+
return resource
|
|
699
|
+
},
|
|
700
|
+
setMetaDescription: (
|
|
701
|
+
context: RepositoryContext,
|
|
702
|
+
resource: Writable<Product>,
|
|
703
|
+
{ metaDescription, staged }: ProductSetMetaDescriptionAction
|
|
704
|
+
) => {
|
|
705
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
706
|
+
resource.masterData.staged.metaDescription = metaDescription
|
|
707
|
+
if (!onlyStaged) {
|
|
708
|
+
resource.masterData.current.metaDescription = metaDescription
|
|
709
|
+
}
|
|
710
|
+
checkForStagedChanges(resource)
|
|
711
|
+
return resource
|
|
712
|
+
},
|
|
713
|
+
setMetaKeywords: (
|
|
714
|
+
context: RepositoryContext,
|
|
715
|
+
resource: Writable<Product>,
|
|
716
|
+
{ metaKeywords, staged }: ProductSetMetaKeywordsAction
|
|
717
|
+
) => {
|
|
718
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
719
|
+
resource.masterData.staged.metaKeywords = metaKeywords
|
|
720
|
+
if (!onlyStaged) {
|
|
721
|
+
resource.masterData.current.metaKeywords = metaKeywords
|
|
722
|
+
}
|
|
723
|
+
checkForStagedChanges(resource)
|
|
724
|
+
return resource
|
|
725
|
+
},
|
|
726
|
+
addVariant: (
|
|
727
|
+
context: RepositoryContext,
|
|
728
|
+
resource: Writable<Product>,
|
|
729
|
+
{
|
|
730
|
+
sku,
|
|
731
|
+
key,
|
|
732
|
+
prices,
|
|
733
|
+
images,
|
|
734
|
+
attributes,
|
|
735
|
+
staged,
|
|
736
|
+
assets,
|
|
737
|
+
}: ProductAddVariantAction
|
|
738
|
+
) => {
|
|
739
|
+
const variantDraft: ProductVariantDraft = {
|
|
740
|
+
sku: sku,
|
|
741
|
+
key: key,
|
|
742
|
+
prices: prices,
|
|
743
|
+
images: images,
|
|
744
|
+
attributes: attributes,
|
|
745
|
+
assets: assets,
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const dataStaged = resource.masterData.staged
|
|
749
|
+
const allVariants = [
|
|
750
|
+
dataStaged.masterVariant,
|
|
751
|
+
...(dataStaged.variants ?? []),
|
|
752
|
+
]
|
|
753
|
+
const maxId = allVariants.reduce(
|
|
754
|
+
(max, element) => (element.id > max ? element.id : max),
|
|
755
|
+
0
|
|
756
|
+
)
|
|
757
|
+
const variant = variantFromDraft(maxId + 1, variantDraft)
|
|
758
|
+
dataStaged.variants.push(variant)
|
|
759
|
+
|
|
760
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
761
|
+
|
|
762
|
+
if (!onlyStaged) {
|
|
763
|
+
resource.masterData.current.variants.push(variant)
|
|
764
|
+
}
|
|
765
|
+
checkForStagedChanges(resource)
|
|
766
|
+
|
|
767
|
+
return resource
|
|
768
|
+
},
|
|
769
|
+
removeVariant: (
|
|
770
|
+
context: RepositoryContext,
|
|
771
|
+
resource: Writable<Product>,
|
|
772
|
+
{ id, sku, staged }: ProductRemoveVariantAction
|
|
773
|
+
) => {
|
|
774
|
+
const removeVariant = (data: Writable<ProductData>) => {
|
|
775
|
+
const { variant, isMasterVariant, variantIndex } = getVariant(
|
|
776
|
+
data,
|
|
777
|
+
id,
|
|
778
|
+
sku
|
|
779
|
+
)
|
|
780
|
+
if (!variant) {
|
|
781
|
+
throw new Error(
|
|
782
|
+
`Variant with id ${id} or sku ${sku} not found on product ${resource.id}`
|
|
783
|
+
)
|
|
784
|
+
}
|
|
785
|
+
if (isMasterVariant) {
|
|
786
|
+
throw new Error(
|
|
787
|
+
`Can not remove the variant [ID:${id}] for [Product:${resource.id}] since it's the master variant`
|
|
788
|
+
)
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
data.variants.splice(variantIndex, 1)
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
795
|
+
|
|
796
|
+
removeVariant(resource.masterData.staged)
|
|
797
|
+
|
|
798
|
+
if (!onlyStaged) {
|
|
799
|
+
removeVariant(resource.masterData.current)
|
|
800
|
+
}
|
|
801
|
+
checkForStagedChanges(resource)
|
|
802
|
+
|
|
803
|
+
return resource
|
|
804
|
+
},
|
|
805
|
+
changeMasterVariant: (
|
|
806
|
+
context: RepositoryContext,
|
|
807
|
+
resource: Writable<Product>,
|
|
808
|
+
{ variantId, sku, staged }: ProductChangeMasterVariantAction
|
|
809
|
+
) => {
|
|
810
|
+
const setMaster = (data: Writable<ProductData>) => {
|
|
811
|
+
const { variant, isMasterVariant, variantIndex } = getVariant(
|
|
812
|
+
data,
|
|
813
|
+
variantId,
|
|
814
|
+
sku
|
|
815
|
+
)
|
|
816
|
+
if (!variant) {
|
|
817
|
+
throw new Error(
|
|
818
|
+
`Variant with id ${variantId} or sku ${sku} not found on product ${resource.id}`
|
|
819
|
+
)
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
if (!isMasterVariant) {
|
|
823
|
+
// Save previous master variant
|
|
824
|
+
const masterVariantPrev = data.masterVariant
|
|
825
|
+
data.masterVariant = variant
|
|
826
|
+
// Remove new master from variants
|
|
827
|
+
data.variants.splice(variantIndex, 1)
|
|
828
|
+
// Add previous master to variants
|
|
829
|
+
data.variants.push(masterVariantPrev)
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
834
|
+
|
|
835
|
+
setMaster(resource.masterData.staged)
|
|
836
|
+
|
|
837
|
+
if (!onlyStaged) {
|
|
838
|
+
setMaster(resource.masterData.current)
|
|
839
|
+
}
|
|
840
|
+
checkForStagedChanges(resource)
|
|
841
|
+
|
|
842
|
+
return resource
|
|
843
|
+
},
|
|
844
|
+
setTaxCategory: (
|
|
845
|
+
context: RepositoryContext,
|
|
846
|
+
resource: Writable<Product>,
|
|
847
|
+
{ taxCategory }: ProductSetTaxCategoryAction
|
|
848
|
+
) => {
|
|
849
|
+
let taxCategoryReference: TaxCategoryReference | undefined = undefined
|
|
850
|
+
if (taxCategory) {
|
|
851
|
+
taxCategoryReference =
|
|
852
|
+
getReferenceFromResourceIdentifier<TaxCategoryReference>(
|
|
853
|
+
taxCategory,
|
|
854
|
+
context.projectKey,
|
|
855
|
+
this._storage
|
|
856
|
+
)
|
|
857
|
+
} else {
|
|
858
|
+
throw new CommercetoolsError<InvalidJsonInputError>(
|
|
859
|
+
{
|
|
860
|
+
code: 'InvalidJsonInput',
|
|
861
|
+
message: 'Request body does not contain valid JSON.',
|
|
862
|
+
detailedErrorMessage:
|
|
863
|
+
'actions -> taxCategory: Missing required value',
|
|
864
|
+
},
|
|
865
|
+
400
|
|
866
|
+
)
|
|
867
|
+
}
|
|
868
|
+
resource.taxCategory = taxCategoryReference
|
|
869
|
+
return resource
|
|
870
|
+
},
|
|
871
|
+
addToCategory: (
|
|
872
|
+
context: RepositoryContext,
|
|
873
|
+
resource: Writable<Product>,
|
|
874
|
+
{ category, staged, orderHint }: ProductAddToCategoryAction
|
|
875
|
+
) => {
|
|
876
|
+
const addCategory = (data: Writable<ProductData>) => {
|
|
877
|
+
if (category) {
|
|
878
|
+
data.categories.push(
|
|
879
|
+
getReferenceFromResourceIdentifier<CategoryReference>(
|
|
880
|
+
category,
|
|
881
|
+
context.projectKey,
|
|
882
|
+
this._storage
|
|
883
|
+
)
|
|
884
|
+
)
|
|
885
|
+
} else {
|
|
886
|
+
throw new CommercetoolsError<InvalidJsonInputError>(
|
|
887
|
+
{
|
|
888
|
+
code: 'InvalidJsonInput',
|
|
889
|
+
message: 'Request body does not contain valid JSON.',
|
|
890
|
+
detailedErrorMessage:
|
|
891
|
+
'actions -> category: Missing required value',
|
|
892
|
+
},
|
|
893
|
+
400
|
|
894
|
+
)
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
899
|
+
|
|
900
|
+
addCategory(resource.masterData.staged)
|
|
901
|
+
|
|
902
|
+
if (!onlyStaged) {
|
|
903
|
+
addCategory(resource.masterData.current)
|
|
904
|
+
}
|
|
905
|
+
checkForStagedChanges(resource)
|
|
906
|
+
|
|
907
|
+
return resource
|
|
908
|
+
},
|
|
909
|
+
removeFromCategory: (
|
|
910
|
+
context: RepositoryContext,
|
|
911
|
+
resource: Writable<Product>,
|
|
912
|
+
{ category, staged }: ProductRemoveFromCategoryAction
|
|
913
|
+
) => {
|
|
914
|
+
const removeCategory = (data: Writable<ProductData>) => {
|
|
915
|
+
if (category) {
|
|
916
|
+
const resolvedCategory =
|
|
917
|
+
getReferenceFromResourceIdentifier<CategoryReference>(
|
|
918
|
+
category,
|
|
919
|
+
context.projectKey,
|
|
920
|
+
this._storage
|
|
921
|
+
)
|
|
922
|
+
|
|
923
|
+
const foundCategory = data.categories.find(
|
|
924
|
+
(productCategory: CategoryReference) => {
|
|
925
|
+
if (productCategory.id == resolvedCategory.id) {
|
|
926
|
+
return productCategory
|
|
927
|
+
}
|
|
928
|
+
return false
|
|
929
|
+
}
|
|
930
|
+
)
|
|
931
|
+
|
|
932
|
+
if (!foundCategory) {
|
|
933
|
+
throw new CommercetoolsError<InvalidOperationError>(
|
|
934
|
+
{
|
|
935
|
+
code: 'InvalidOperation',
|
|
936
|
+
message:
|
|
937
|
+
`Cannot remove from category '${resolvedCategory.id}' because product ` +
|
|
938
|
+
`'${resource.masterData.current.name}' is not in that category.`,
|
|
939
|
+
},
|
|
940
|
+
400
|
|
941
|
+
)
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
data.categories = data.categories.filter(
|
|
945
|
+
(productCategory: CategoryReference) => {
|
|
946
|
+
if (productCategory.id == resolvedCategory.id) {
|
|
947
|
+
return false
|
|
948
|
+
}
|
|
949
|
+
return true
|
|
950
|
+
}
|
|
951
|
+
)
|
|
952
|
+
} else {
|
|
953
|
+
throw new CommercetoolsError<InvalidJsonInputError>(
|
|
954
|
+
{
|
|
955
|
+
code: 'InvalidJsonInput',
|
|
956
|
+
message: 'Request body does not contain valid JSON.',
|
|
957
|
+
detailedErrorMessage:
|
|
958
|
+
'actions -> category: Missing required value',
|
|
959
|
+
},
|
|
960
|
+
400
|
|
961
|
+
)
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
966
|
+
removeCategory(resource.masterData.staged)
|
|
967
|
+
|
|
968
|
+
if (!onlyStaged) {
|
|
969
|
+
removeCategory(resource.masterData.current)
|
|
970
|
+
}
|
|
971
|
+
checkForStagedChanges(resource)
|
|
972
|
+
|
|
973
|
+
return resource
|
|
974
|
+
},
|
|
975
|
+
transitionState: (
|
|
976
|
+
context: RepositoryContext,
|
|
977
|
+
resource: Writable<Product>,
|
|
978
|
+
{ state, force }: ProductTransitionStateAction
|
|
979
|
+
) => {
|
|
980
|
+
let productStateReference: StateReference | undefined = undefined
|
|
981
|
+
if (state) {
|
|
982
|
+
productStateReference =
|
|
983
|
+
getReferenceFromResourceIdentifier<StateReference>(
|
|
984
|
+
state,
|
|
985
|
+
context.projectKey,
|
|
986
|
+
this._storage
|
|
987
|
+
)
|
|
988
|
+
resource.state = productStateReference
|
|
989
|
+
} else {
|
|
990
|
+
throw new CommercetoolsError<InvalidJsonInputError>(
|
|
991
|
+
{
|
|
992
|
+
code: 'InvalidJsonInput',
|
|
993
|
+
message: 'Request body does not contain valid JSON.',
|
|
994
|
+
detailedErrorMessage: 'actions -> state: Missing required value',
|
|
995
|
+
},
|
|
996
|
+
400
|
|
997
|
+
)
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
return resource
|
|
1001
|
+
},
|
|
528
1002
|
|
|
529
|
-
// 'changeName': () => {},
|
|
530
|
-
// 'changeSlug': () => {},
|
|
531
|
-
// 'addVariant': () => {},
|
|
532
|
-
// 'removeVariant': () => {},
|
|
533
|
-
// 'changeMasterVariant': () => {},
|
|
534
1003
|
// 'setPrices': () => {},
|
|
535
1004
|
// 'setProductPriceCustomType': () => {},
|
|
536
1005
|
// 'setProductPriceCustomField': () => {},
|
|
537
1006
|
// 'setDiscountedPrice': () => {},
|
|
538
1007
|
// 'setAttributeInAllVariants': () => {},
|
|
539
|
-
// 'addToCategory': () => {},
|
|
540
1008
|
// 'setCategoryOrderHint': () => {},
|
|
541
|
-
// 'removeFromCategory': () => {},
|
|
542
|
-
// 'setTaxCategory': () => {},
|
|
543
1009
|
// 'setSku': () => {},
|
|
544
1010
|
// 'setProductVariantKey': () => {},
|
|
545
1011
|
// 'setImageLabel': () => {},
|
|
@@ -554,12 +1020,8 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
|
|
|
554
1020
|
// 'setAssetCustomType': () => {},
|
|
555
1021
|
// 'setAssetCustomField': () => {},
|
|
556
1022
|
// 'setSearchKeywords': () => {},
|
|
557
|
-
// 'setMetaTitle': () => {},
|
|
558
|
-
// 'setMetaDescription': () => {},
|
|
559
|
-
// 'setMetaKeywords': () => {},
|
|
560
1023
|
// 'revertStagedChanges': () => {},
|
|
561
1024
|
// 'revertStagedVariantChanges': () => {},
|
|
562
|
-
// 'transitionState': () => {},
|
|
563
1025
|
}
|
|
564
1026
|
}
|
|
565
1027
|
|
|
@@ -616,6 +1078,7 @@ const variantFromDraft = (
|
|
|
616
1078
|
): ProductVariant => ({
|
|
617
1079
|
id: variantId,
|
|
618
1080
|
sku: variant?.sku,
|
|
1081
|
+
key: variant?.key,
|
|
619
1082
|
attributes: variant?.attributes ?? [],
|
|
620
1083
|
prices: variant?.prices?.map(priceFromDraft),
|
|
621
1084
|
assets: [],
|
|
@@ -624,6 +1087,7 @@ const variantFromDraft = (
|
|
|
624
1087
|
|
|
625
1088
|
const priceFromDraft = (draft: PriceDraft): Price => ({
|
|
626
1089
|
id: uuidv4(),
|
|
1090
|
+
key: draft.key,
|
|
627
1091
|
country: draft.country,
|
|
628
1092
|
value: createTypedMoney(draft.value),
|
|
629
1093
|
})
|