@labdigital/commercetools-mock 1.0.0 → 1.1.1
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.global.js +117 -0
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +117 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +117 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
- package/src/repositories/product.ts +163 -3
- package/src/services/product.test.ts +124 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@labdigital/commercetools-mock",
|
|
3
3
|
"author": "Michael van Tellingen",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.1.1",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/commercetools--mock.esm.js",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@babel/preset-env": "^7.18.9",
|
|
50
50
|
"@babel/preset-typescript": "^7.18.6",
|
|
51
|
-
"@changesets/cli": "^2.26.0",
|
|
52
51
|
"@changesets/changelog-github": "^0.4.8",
|
|
52
|
+
"@changesets/cli": "^2.26.0",
|
|
53
53
|
"@commercetools/platform-sdk": "4.0.0",
|
|
54
54
|
"@labdigital/eslint-config-node": "0.0.5",
|
|
55
55
|
"@types/basic-auth": "^1.1.3",
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
"got": "^11.8.3",
|
|
73
73
|
"husky": "^7.0.4",
|
|
74
74
|
"jest": "^28.1.3",
|
|
75
|
+
"nodemon": "^2.0.22",
|
|
75
76
|
"prettier": "^2.7.1",
|
|
76
77
|
"timekeeper": "^2.2.0",
|
|
77
78
|
"ts-node": "^10.4.0",
|
|
@@ -84,7 +85,7 @@
|
|
|
84
85
|
"@commercetools/platform-sdk": "^2.4.1"
|
|
85
86
|
},
|
|
86
87
|
"scripts": {
|
|
87
|
-
"start": "
|
|
88
|
+
"start": "nodemon --watch src --exec 'node -r esbuild-register' src/server.ts",
|
|
88
89
|
"build": "tsup",
|
|
89
90
|
"build:server": "esbuild src/server.ts --bundle --outfile=dist/server.js --platform=node",
|
|
90
91
|
"publish:ci": "pnpm build && pnpm changeset publish",
|
|
@@ -15,6 +15,9 @@ import {
|
|
|
15
15
|
ProductVariant,
|
|
16
16
|
ProductVariantDraft,
|
|
17
17
|
ProductMoveImageToPositionAction,
|
|
18
|
+
ProductChangePriceAction,
|
|
19
|
+
ProductAddPriceAction,
|
|
20
|
+
ProductRemovePriceAction,
|
|
18
21
|
} from '@commercetools/platform-sdk'
|
|
19
22
|
import { v4 as uuidv4 } from 'uuid'
|
|
20
23
|
import { Writable } from '../types'
|
|
@@ -361,15 +364,171 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
|
|
|
361
364
|
return resource
|
|
362
365
|
},
|
|
363
366
|
|
|
367
|
+
addPrice: (
|
|
368
|
+
context: RepositoryContext,
|
|
369
|
+
resource: Writable<Product>,
|
|
370
|
+
{ variantId, sku, price, staged }: ProductAddPriceAction
|
|
371
|
+
) => {
|
|
372
|
+
const addVariantPrice = (data: Writable<ProductData>) => {
|
|
373
|
+
const { variant, isMasterVariant, variantIndex } = getVariant(
|
|
374
|
+
data,
|
|
375
|
+
variantId,
|
|
376
|
+
sku
|
|
377
|
+
)
|
|
378
|
+
if (!variant) {
|
|
379
|
+
throw new Error(
|
|
380
|
+
`Variant with id ${variantId} or sku ${sku} not found on product ${resource.id}`
|
|
381
|
+
)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (variant.prices === undefined) {
|
|
385
|
+
variant.prices = [priceFromDraft(price)]
|
|
386
|
+
} else {
|
|
387
|
+
variant.prices.push(priceFromDraft(price))
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (isMasterVariant) {
|
|
391
|
+
data.masterVariant = variant
|
|
392
|
+
} else {
|
|
393
|
+
data.variants[variantIndex] = variant
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// If true, only the staged Attribute is set. If false, both current and
|
|
398
|
+
// staged Attribute is set. Default is true
|
|
399
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
400
|
+
|
|
401
|
+
// Write the attribute to the staged data
|
|
402
|
+
addVariantPrice(resource.masterData.staged)
|
|
403
|
+
|
|
404
|
+
// Also write to published data is isStaged = false
|
|
405
|
+
// if isStaged is false we set the attribute on both the staged and
|
|
406
|
+
// published data.
|
|
407
|
+
if (!onlyStaged) {
|
|
408
|
+
addVariantPrice(resource.masterData.current)
|
|
409
|
+
}
|
|
410
|
+
checkForStagedChanges(resource)
|
|
411
|
+
|
|
412
|
+
return resource
|
|
413
|
+
},
|
|
414
|
+
changePrice: (
|
|
415
|
+
context: RepositoryContext,
|
|
416
|
+
resource: Writable<Product>,
|
|
417
|
+
{ priceId, price, staged }: ProductChangePriceAction
|
|
418
|
+
) => {
|
|
419
|
+
const changeVariantPrice = (data: Writable<ProductData>) => {
|
|
420
|
+
const allVariants = [data.masterVariant, ...(data.variants ?? [])]
|
|
421
|
+
const priceVariant = allVariants.find((variant) =>
|
|
422
|
+
variant.prices?.some((x) => x.id === priceId)
|
|
423
|
+
)
|
|
424
|
+
if (!priceVariant) {
|
|
425
|
+
throw new Error(
|
|
426
|
+
`Price with id ${priceId} not found on product ${resource.id}`
|
|
427
|
+
)
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const { variant, isMasterVariant, variantIndex } = getVariant(
|
|
431
|
+
data,
|
|
432
|
+
priceVariant.id,
|
|
433
|
+
priceVariant.sku
|
|
434
|
+
)
|
|
435
|
+
if (!variant) {
|
|
436
|
+
throw new Error(
|
|
437
|
+
`Variant with id ${priceVariant.id} or sku ${priceVariant.sku} not found on product ${resource.id}`
|
|
438
|
+
)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
variant.prices = variant.prices?.map((x) => {
|
|
442
|
+
if (x.id === priceId) {
|
|
443
|
+
return { ...x, ...price } as Price
|
|
444
|
+
}
|
|
445
|
+
return x
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
if (isMasterVariant) {
|
|
449
|
+
data.masterVariant = variant
|
|
450
|
+
} else {
|
|
451
|
+
data.variants[variantIndex] = variant
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// If true, only the staged Attribute is set. If false, both current and
|
|
456
|
+
// staged Attribute is set. Default is true
|
|
457
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
458
|
+
|
|
459
|
+
// Write the attribute to the staged data
|
|
460
|
+
changeVariantPrice(resource.masterData.staged)
|
|
461
|
+
|
|
462
|
+
// Also write to published data is isStaged = false
|
|
463
|
+
// if isStaged is false we set the attribute on both the staged and
|
|
464
|
+
// published data.
|
|
465
|
+
if (!onlyStaged) {
|
|
466
|
+
changeVariantPrice(resource.masterData.current)
|
|
467
|
+
}
|
|
468
|
+
checkForStagedChanges(resource)
|
|
469
|
+
|
|
470
|
+
return resource
|
|
471
|
+
},
|
|
472
|
+
removePrice: (
|
|
473
|
+
context: RepositoryContext,
|
|
474
|
+
resource: Writable<Product>,
|
|
475
|
+
{ priceId, staged }: ProductRemovePriceAction
|
|
476
|
+
) => {
|
|
477
|
+
const removeVariantPrice = (data: Writable<ProductData>) => {
|
|
478
|
+
const allVariants = [data.masterVariant, ...(data.variants ?? [])]
|
|
479
|
+
const priceVariant = allVariants.find((variant) =>
|
|
480
|
+
variant.prices?.some((x) => x.id === priceId)
|
|
481
|
+
)
|
|
482
|
+
if (!priceVariant) {
|
|
483
|
+
throw new Error(
|
|
484
|
+
`Price with id ${priceId} not found on product ${resource.id}`
|
|
485
|
+
)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const { variant, isMasterVariant, variantIndex } = getVariant(
|
|
489
|
+
data,
|
|
490
|
+
priceVariant.id,
|
|
491
|
+
priceVariant.sku
|
|
492
|
+
)
|
|
493
|
+
if (!variant) {
|
|
494
|
+
throw new Error(
|
|
495
|
+
`Variant with id ${priceVariant.id} or sku ${priceVariant.sku} not found on product ${resource.id}`
|
|
496
|
+
)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
variant.prices = variant.prices?.filter((x) => x.id !== priceId)
|
|
500
|
+
|
|
501
|
+
if (isMasterVariant) {
|
|
502
|
+
data.masterVariant = variant
|
|
503
|
+
} else {
|
|
504
|
+
data.variants[variantIndex] = variant
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// If true, only the staged Attribute is set. If false, both current and
|
|
509
|
+
// staged Attribute is set. Default is true
|
|
510
|
+
const onlyStaged = staged !== undefined ? staged : true
|
|
511
|
+
|
|
512
|
+
// Write the attribute to the staged data
|
|
513
|
+
removeVariantPrice(resource.masterData.staged)
|
|
514
|
+
|
|
515
|
+
// Also write to published data is isStaged = false
|
|
516
|
+
// if isStaged is false we set the attribute on both the staged and
|
|
517
|
+
// published data.
|
|
518
|
+
if (!onlyStaged) {
|
|
519
|
+
removeVariantPrice(resource.masterData.current)
|
|
520
|
+
}
|
|
521
|
+
checkForStagedChanges(resource)
|
|
522
|
+
|
|
523
|
+
return resource
|
|
524
|
+
},
|
|
525
|
+
|
|
364
526
|
// 'changeName': () => {},
|
|
365
527
|
// 'changeSlug': () => {},
|
|
366
528
|
// 'addVariant': () => {},
|
|
367
529
|
// 'removeVariant': () => {},
|
|
368
530
|
// 'changeMasterVariant': () => {},
|
|
369
|
-
// 'addPrice': () => {},
|
|
370
531
|
// 'setPrices': () => {},
|
|
371
|
-
// 'changePrice': () => {},
|
|
372
|
-
// 'removePrice': () => {},
|
|
373
532
|
// 'setProductPriceCustomType': () => {},
|
|
374
533
|
// 'setProductPriceCustomField': () => {},
|
|
375
534
|
// 'setDiscountedPrice': () => {},
|
|
@@ -462,6 +621,7 @@ const variantFromDraft = (
|
|
|
462
621
|
|
|
463
622
|
const priceFromDraft = (draft: PriceDraft): Price => ({
|
|
464
623
|
id: uuidv4(),
|
|
624
|
+
country: draft.country,
|
|
465
625
|
value: {
|
|
466
626
|
currencyCode: draft.value.currencyCode,
|
|
467
627
|
centAmount: draft.value.centAmount,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Image,
|
|
3
|
+
PriceDraft,
|
|
3
4
|
Product,
|
|
4
5
|
ProductData,
|
|
5
6
|
ProductDraft,
|
|
@@ -26,6 +27,15 @@ const publishedProductDraft: ProductDraft = {
|
|
|
26
27
|
value: 'test',
|
|
27
28
|
},
|
|
28
29
|
],
|
|
30
|
+
prices: [
|
|
31
|
+
{
|
|
32
|
+
country: 'NL',
|
|
33
|
+
value: {
|
|
34
|
+
currencyCode: 'EUR',
|
|
35
|
+
centAmount: 1000,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
],
|
|
29
39
|
},
|
|
30
40
|
variants: [
|
|
31
41
|
{
|
|
@@ -36,6 +46,15 @@ const publishedProductDraft: ProductDraft = {
|
|
|
36
46
|
value: 'test2',
|
|
37
47
|
},
|
|
38
48
|
],
|
|
49
|
+
prices: [
|
|
50
|
+
{
|
|
51
|
+
country: 'NL',
|
|
52
|
+
value: {
|
|
53
|
+
currencyCode: 'EUR',
|
|
54
|
+
centAmount: 2000,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
],
|
|
39
58
|
},
|
|
40
59
|
],
|
|
41
60
|
slug: {
|
|
@@ -402,4 +421,109 @@ describe('Product update actions', () => {
|
|
|
402
421
|
{ url: 'http://example.com/image1', dimensions: { w: 100, h: 100 } },
|
|
403
422
|
])
|
|
404
423
|
})
|
|
424
|
+
|
|
425
|
+
test('addPrice variant', async () => {
|
|
426
|
+
assert(productPublished, 'product not created')
|
|
427
|
+
|
|
428
|
+
const priceDraft: PriceDraft = {
|
|
429
|
+
country: 'BE',
|
|
430
|
+
value: {
|
|
431
|
+
currencyCode: 'EUR',
|
|
432
|
+
centAmount: 3000,
|
|
433
|
+
},
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const response = await supertest(ctMock.app)
|
|
437
|
+
.post(`/dummy/products/${productPublished.id}`)
|
|
438
|
+
.send({
|
|
439
|
+
version: 1,
|
|
440
|
+
actions: [
|
|
441
|
+
{
|
|
442
|
+
action: 'addPrice',
|
|
443
|
+
price: priceDraft,
|
|
444
|
+
variantId: 1,
|
|
445
|
+
},
|
|
446
|
+
],
|
|
447
|
+
})
|
|
448
|
+
expect(response.status).toBe(200)
|
|
449
|
+
expect(response.body.version).toBe(2)
|
|
450
|
+
expect(response.body.masterData.staged.masterVariant.prices).toMatchObject([
|
|
451
|
+
{
|
|
452
|
+
country: 'NL',
|
|
453
|
+
value: {
|
|
454
|
+
currencyCode: 'EUR',
|
|
455
|
+
centAmount: 1000,
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
country: 'BE',
|
|
460
|
+
value: {
|
|
461
|
+
currencyCode: 'EUR',
|
|
462
|
+
centAmount: 3000,
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
])
|
|
466
|
+
})
|
|
467
|
+
|
|
468
|
+
test('changePrice variant', async () => {
|
|
469
|
+
assert(productPublished, 'product not created')
|
|
470
|
+
const priceId =
|
|
471
|
+
productPublished?.masterData.current.masterVariant.prices?.[0].id
|
|
472
|
+
assert(priceId)
|
|
473
|
+
|
|
474
|
+
const priceDraft: PriceDraft = {
|
|
475
|
+
country: 'BE',
|
|
476
|
+
value: {
|
|
477
|
+
currencyCode: 'EUR',
|
|
478
|
+
centAmount: 3000,
|
|
479
|
+
},
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const response = await supertest(ctMock.app)
|
|
483
|
+
.post(`/dummy/products/${productPublished.id}`)
|
|
484
|
+
.send({
|
|
485
|
+
version: 1,
|
|
486
|
+
actions: [
|
|
487
|
+
{
|
|
488
|
+
action: 'changePrice',
|
|
489
|
+
priceId,
|
|
490
|
+
price: priceDraft,
|
|
491
|
+
},
|
|
492
|
+
],
|
|
493
|
+
})
|
|
494
|
+
expect(response.status).toBe(200)
|
|
495
|
+
expect(response.body.version).toBe(2)
|
|
496
|
+
expect(response.body.masterData.staged.masterVariant.prices).toMatchObject([
|
|
497
|
+
{
|
|
498
|
+
id: priceId,
|
|
499
|
+
country: 'BE',
|
|
500
|
+
value: {
|
|
501
|
+
currencyCode: 'EUR',
|
|
502
|
+
centAmount: 3000,
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
])
|
|
506
|
+
})
|
|
507
|
+
|
|
508
|
+
test('removePrice variant', async () => {
|
|
509
|
+
assert(productPublished, 'product not created')
|
|
510
|
+
const priceId =
|
|
511
|
+
productPublished?.masterData.current.masterVariant.prices?.[0].id
|
|
512
|
+
assert(priceId)
|
|
513
|
+
|
|
514
|
+
const response = await supertest(ctMock.app)
|
|
515
|
+
.post(`/dummy/products/${productPublished.id}`)
|
|
516
|
+
.send({
|
|
517
|
+
version: 1,
|
|
518
|
+
actions: [
|
|
519
|
+
{
|
|
520
|
+
action: 'removePrice',
|
|
521
|
+
priceId,
|
|
522
|
+
},
|
|
523
|
+
],
|
|
524
|
+
})
|
|
525
|
+
expect(response.status).toBe(200)
|
|
526
|
+
expect(response.body.version).toBe(2)
|
|
527
|
+
expect(response.body.masterData.staged.masterVariant.prices).toHaveLength(0)
|
|
528
|
+
})
|
|
405
529
|
})
|