@labdigital/commercetools-mock 2.58.0 → 2.59.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@labdigital/commercetools-mock",
3
- "version": "2.58.0",
3
+ "version": "2.59.0",
4
4
  "license": "MIT",
5
5
  "author": "Michael van Tellingen",
6
6
  "type": "module",
@@ -21,7 +21,7 @@
21
21
  "express": "5.1.0",
22
22
  "light-my-request": "6.6.0",
23
23
  "morgan": "1.10.0",
24
- "msw": "2.7.3",
24
+ "msw": "2.8.4",
25
25
  "uuid": "11.1.0",
26
26
  "zod": "3.24.2",
27
27
  "zod-validation-error": "3.4.0"
@@ -26,6 +26,8 @@ import type {
26
26
  CartSetCustomTypeAction,
27
27
  CartSetCustomerEmailAction,
28
28
  CartSetDirectDiscountsAction,
29
+ CartSetLineItemCustomFieldAction,
30
+ CartSetLineItemCustomTypeAction,
29
31
  CartSetLineItemShippingDetailsAction,
30
32
  CartSetLocaleAction,
31
33
  CartSetShippingAddressAction,
@@ -662,6 +664,82 @@ export class CartUpdateHandler
662
664
  );
663
665
  }
664
666
 
667
+ setLineItemCustomField(
668
+ context: RepositoryContext,
669
+ resource: Writable<Cart>,
670
+ {
671
+ lineItemId,
672
+ lineItemKey,
673
+ name,
674
+ value,
675
+ action,
676
+ }: CartSetLineItemCustomFieldAction,
677
+ ) {
678
+ const lineItem = resource.lineItems.find(
679
+ (x) =>
680
+ (lineItemId && x.id === lineItemId) ||
681
+ (lineItemKey && x.key === lineItemKey),
682
+ );
683
+
684
+ if (!lineItem) {
685
+ // Check if line item is found
686
+ throw new CommercetoolsError<GeneralError>({
687
+ code: "General",
688
+ message: lineItemKey
689
+ ? `A line item with key '${lineItemKey}' not found.`
690
+ : `A line item with ID '${lineItemId}' not found.`,
691
+ });
692
+ }
693
+
694
+ if (!lineItem.custom) {
695
+ throw new Error("Resource has no custom field");
696
+ }
697
+
698
+ lineItem.custom.fields[name] = value;
699
+ }
700
+
701
+ setLineItemCustomType(
702
+ context: RepositoryContext,
703
+ resource: Writable<Cart>,
704
+ { lineItemId, lineItemKey, type, fields }: CartSetLineItemCustomTypeAction,
705
+ ) {
706
+ const lineItem = resource.lineItems.find(
707
+ (x) =>
708
+ (lineItemId && x.id === lineItemId) ||
709
+ (lineItemKey && x.key === lineItemKey),
710
+ );
711
+
712
+ if (!lineItem) {
713
+ // Check if line item is found
714
+ throw new CommercetoolsError<GeneralError>({
715
+ code: "General",
716
+ message: lineItemKey
717
+ ? `A line item with key '${lineItemKey}' not found.`
718
+ : `A line item with ID '${lineItemId}' not found.`,
719
+ });
720
+ }
721
+
722
+ if (!type) {
723
+ lineItem.custom = undefined;
724
+ } else {
725
+ const resolvedType = this._storage.getByResourceIdentifier(
726
+ context.projectKey,
727
+ type,
728
+ );
729
+ if (!resolvedType) {
730
+ throw new Error(`Type ${type} not found`);
731
+ }
732
+
733
+ lineItem.custom = {
734
+ type: {
735
+ typeId: "type",
736
+ id: resolvedType.id,
737
+ },
738
+ fields: fields || {},
739
+ };
740
+ }
741
+ }
742
+
665
743
  setLineItemShippingDetails(
666
744
  context: RepositoryContext,
667
745
  resource: Writable<Cart>,
@@ -1,5 +1,6 @@
1
1
  import type {
2
2
  CustomLineItemReturnItem,
3
+ GeneralError,
3
4
  LineItemReturnItem,
4
5
  Order,
5
6
  OrderAddPaymentAction,
@@ -9,10 +10,13 @@ import type {
9
10
  OrderChangeShipmentStateAction,
10
11
  OrderSetBillingAddressAction,
11
12
  OrderSetCustomFieldAction,
13
+ OrderSetCustomLineItemCustomTypeAction,
12
14
  OrderSetCustomTypeAction,
13
15
  OrderSetCustomerEmailAction,
14
16
  OrderSetCustomerIdAction,
15
17
  OrderSetDeliveryCustomFieldAction,
18
+ OrderSetLineItemCustomFieldAction,
19
+ OrderSetLineItemCustomTypeAction,
16
20
  OrderSetLocaleAction,
17
21
  OrderSetOrderNumberAction,
18
22
  OrderSetParcelCustomFieldAction,
@@ -27,6 +31,7 @@ import type {
27
31
  Store,
28
32
  SyncInfo,
29
33
  } from "@commercetools/platform-sdk";
34
+ import { CommercetoolsError } from "~src/exceptions";
30
35
  import { getBaseResourceProperties } from "~src/helpers";
31
36
  import type { Writable } from "~src/types";
32
37
  import type { RepositoryContext, UpdateHandlerInterface } from "../abstract";
@@ -205,6 +210,82 @@ export class OrderUpdateHandler
205
210
  }
206
211
  }
207
212
 
213
+ setLineItemCustomField(
214
+ context: RepositoryContext,
215
+ resource: Order,
216
+ {
217
+ lineItemId,
218
+ lineItemKey,
219
+ name,
220
+ value,
221
+ action,
222
+ }: OrderSetLineItemCustomFieldAction,
223
+ ) {
224
+ const lineItem = resource.lineItems.find(
225
+ (x) =>
226
+ (lineItemId && x.id === lineItemId) ||
227
+ (lineItemKey && x.key === lineItemKey),
228
+ );
229
+
230
+ if (!lineItem) {
231
+ // Check if line item is found
232
+ throw new CommercetoolsError<GeneralError>({
233
+ code: "General",
234
+ message: lineItemKey
235
+ ? `A line item with key '${lineItemKey}' not found.`
236
+ : `A line item with ID '${lineItemId}' not found.`,
237
+ });
238
+ }
239
+
240
+ if (!lineItem.custom) {
241
+ throw new Error("Resource has no custom field");
242
+ }
243
+
244
+ lineItem.custom.fields[name] = value;
245
+ }
246
+
247
+ setLineItemCustomType(
248
+ context: RepositoryContext,
249
+ resource: Writable<Order>,
250
+ { lineItemId, lineItemKey, type, fields }: OrderSetLineItemCustomTypeAction,
251
+ ) {
252
+ const lineItem = resource.lineItems.find(
253
+ (x) =>
254
+ (lineItemId && x.id === lineItemId) ||
255
+ (lineItemKey && x.key === lineItemKey),
256
+ );
257
+
258
+ if (!lineItem) {
259
+ // Check if line item is found
260
+ throw new CommercetoolsError<GeneralError>({
261
+ code: "General",
262
+ message: lineItemKey
263
+ ? `A line item with key '${lineItemKey}' not found.`
264
+ : `A line item with ID '${lineItemId}' not found.`,
265
+ });
266
+ }
267
+
268
+ if (!type) {
269
+ lineItem.custom = undefined;
270
+ } else {
271
+ const resolvedType = this._storage.getByResourceIdentifier(
272
+ context.projectKey,
273
+ type,
274
+ );
275
+ if (!resolvedType) {
276
+ throw new Error(`Type ${type} not found`);
277
+ }
278
+
279
+ lineItem.custom = {
280
+ type: {
281
+ typeId: "type",
282
+ id: resolvedType.id,
283
+ },
284
+ fields: fields || {},
285
+ };
286
+ }
287
+ }
288
+
208
289
  setLocale(
209
290
  context: RepositoryContext,
210
291
  resource: Writable<Order>,
@@ -219,6 +219,7 @@ export class OrderRepository extends AbstractResourceRepository<"order"> {
219
219
  id: variant.id,
220
220
  sku: variant.sku,
221
221
  price: createPrice(draft.price),
222
+ attributes: variant.attributes,
222
223
  },
223
224
  };
224
225
 
@@ -711,6 +711,176 @@ describe("Cart Update Actions", () => {
711
711
  ]);
712
712
  });
713
713
 
714
+ test("setLineItemCustomField", async () => {
715
+ const product = await supertest(ctMock.app)
716
+ .post("/dummy/products")
717
+ .send(productDraft)
718
+ .then((x) => x.body);
719
+
720
+ assert(product, "product not created");
721
+
722
+ const type = await supertest(ctMock.app)
723
+ .post("/dummy/types")
724
+ .send({
725
+ key: "my-type",
726
+ name: {
727
+ en: "My Type",
728
+ },
729
+ description: {
730
+ en: "My Type Description",
731
+ },
732
+ fieldDefinitions: [
733
+ {
734
+ name: "foo",
735
+ label: {
736
+ en: "foo",
737
+ },
738
+ required: false,
739
+ type: {
740
+ name: "String",
741
+ },
742
+ inputHint: "SingleLine",
743
+ },
744
+ ],
745
+ })
746
+ .then((x) => x.body);
747
+
748
+ assert(type, "type not created");
749
+
750
+ const myCart = await supertest(ctMock.app)
751
+ .post("/dummy/carts")
752
+ .send({
753
+ currency: "EUR",
754
+ lineItems: [
755
+ {
756
+ sku: product.masterData.current.masterVariant.sku,
757
+ quantity: 1,
758
+ custom: {
759
+ type: {
760
+ typeId: "type",
761
+ key: "my-type",
762
+ },
763
+ fields: {},
764
+ },
765
+ },
766
+ ],
767
+ })
768
+ .then((x) => x.body);
769
+
770
+ const lineItem = myCart.lineItems[0];
771
+ assert(lineItem, "lineItem not created");
772
+
773
+ const response = await supertest(ctMock.app)
774
+ .post(`/dummy/carts/${myCart.id}`)
775
+ .send({
776
+ version: myCart.version,
777
+ actions: [
778
+ {
779
+ action: "setLineItemCustomField",
780
+ lineItemId: lineItem.id,
781
+ name: "foo",
782
+ value: "bar",
783
+ },
784
+ ],
785
+ });
786
+
787
+ expect(response.status).toBe(200);
788
+ expect(response.body.version).toBe(2);
789
+ expect(response.body.lineItems).toMatchObject([
790
+ {
791
+ id: lineItem.id,
792
+ custom: {
793
+ fields: {
794
+ foo: "bar",
795
+ },
796
+ },
797
+ },
798
+ ]);
799
+ });
800
+
801
+ test("setLineItemCustomType", async () => {
802
+ const product = await supertest(ctMock.app)
803
+ .post("/dummy/products")
804
+ .send(productDraft)
805
+ .then((x) => x.body);
806
+
807
+ assert(product, "product not created");
808
+
809
+ const type = await supertest(ctMock.app)
810
+ .post("/dummy/types")
811
+ .send({
812
+ key: "my-type",
813
+ name: {
814
+ en: "My Type",
815
+ },
816
+ description: {
817
+ en: "My Type Description",
818
+ },
819
+ fieldDefinitions: [
820
+ {
821
+ name: "foo",
822
+ label: {
823
+ en: "foo",
824
+ },
825
+ required: false,
826
+ type: {
827
+ name: "String",
828
+ },
829
+ inputHint: "SingleLine",
830
+ },
831
+ ],
832
+ })
833
+ .then((x) => x.body);
834
+
835
+ assert(type, "type not created");
836
+
837
+ const myCart = await supertest(ctMock.app)
838
+ .post("/dummy/carts")
839
+ .send({
840
+ currency: "EUR",
841
+ lineItems: [
842
+ {
843
+ sku: product.masterData.current.masterVariant.sku,
844
+ quantity: 1,
845
+ },
846
+ ],
847
+ })
848
+ .then((x) => x.body);
849
+
850
+ const lineItem = myCart.lineItems[0];
851
+ assert(lineItem, "lineItem not created");
852
+
853
+ const response = await supertest(ctMock.app)
854
+ .post(`/dummy/carts/${myCart.id}`)
855
+ .send({
856
+ version: myCart.version,
857
+ actions: [
858
+ {
859
+ action: "setLineItemCustomType",
860
+ lineItemId: lineItem.id,
861
+ type: {
862
+ typeId: "type",
863
+ key: "my-type",
864
+ },
865
+ },
866
+ ],
867
+ });
868
+
869
+ expect(response.status).toBe(200);
870
+ expect(response.body.version).toBe(2);
871
+ expect(response.body.lineItems).toMatchObject([
872
+ {
873
+ id: lineItem.id,
874
+ custom: {
875
+ type: {
876
+ typeId: "type",
877
+ id: type.id,
878
+ },
879
+ },
880
+ },
881
+ ]);
882
+ });
883
+
714
884
  test("setCustomerEmail", async () => {
715
885
  assert(cart, "cart not created");
716
886
 
@@ -1,5 +1,10 @@
1
1
  import assert from "node:assert";
2
- import type { Order, Payment, State } from "@commercetools/platform-sdk";
2
+ import type {
3
+ CentPrecisionMoney,
4
+ Order,
5
+ Payment,
6
+ State,
7
+ } from "@commercetools/platform-sdk";
3
8
  import supertest from "supertest";
4
9
  import { afterEach, beforeEach, describe, expect, test } from "vitest";
5
10
  import { generateRandomString } from "~src/helpers";
@@ -611,6 +616,236 @@ describe("Order Update Actions", () => {
611
616
  ).toBe("dhl");
612
617
  });
613
618
 
619
+ test("setLineItemCustomField", async () => {
620
+ const order: Order = {
621
+ ...getBaseResourceProperties(),
622
+ version: 1,
623
+ customLineItems: [],
624
+ directDiscounts: [],
625
+ discountCodes: [],
626
+ lineItems: [
627
+ {
628
+ id: "d70b14c8-72cf-4cab-82ba-6339cebe1e79",
629
+ productId: "06028a97-d622-47ac-a194-a3d90baa2b3c",
630
+ productSlug: { "nl-NL": "test-product" },
631
+ productType: { typeId: "product-type", id: "some-uuid" },
632
+ name: { "nl-NL": "test product" },
633
+ custom: {
634
+ type: {
635
+ typeId: "type",
636
+ id: "a493b7bb-d415-450c-b421-e128a8b26569",
637
+ },
638
+ fields: {},
639
+ },
640
+ variant: {
641
+ id: 1,
642
+ sku: "1337",
643
+ attributes: [{ name: "test", value: "test" }],
644
+ prices: [],
645
+ assets: [],
646
+ images: [],
647
+ },
648
+ price: {
649
+ id: "2f59a6c9-6a86-48d3-87f9-fabb3b12fd93",
650
+ value: {
651
+ type: "centPrecision",
652
+ centAmount: 14900,
653
+ currencyCode: "EUR",
654
+ fractionDigits: 2,
655
+ },
656
+ },
657
+ totalPrice: {
658
+ type: "centPrecision",
659
+ currencyCode: "EUR",
660
+ fractionDigits: 2,
661
+ centAmount: 14900,
662
+ },
663
+ taxedPricePortions: [],
664
+ perMethodTaxRate: [],
665
+ quantity: 1,
666
+ discountedPricePerQuantity: [],
667
+ lineItemMode: "Standard",
668
+ priceMode: "Platform",
669
+ state: [],
670
+ },
671
+ ],
672
+ orderState: "Open",
673
+ origin: "Customer",
674
+ refusedGifts: [],
675
+ shipping: [],
676
+ shippingMode: "Single",
677
+ syncInfo: [],
678
+ taxCalculationMode: "LineItemLevel",
679
+ taxMode: "Platform",
680
+ taxRoundingMode: "HalfEven",
681
+ totalPrice: {
682
+ type: "centPrecision",
683
+ centAmount: 14900,
684
+ currencyCode: "EUR",
685
+ fractionDigits: 0,
686
+ },
687
+ };
688
+
689
+ ctMock.project("dummy").add("order", order);
690
+
691
+ const lineItem = order.lineItems[0];
692
+ assert(lineItem, "lineItem not created");
693
+
694
+ const response = await supertest(ctMock.app)
695
+ .post(`/dummy/orders/${order.id}`)
696
+ .send({
697
+ version: order.version,
698
+ actions: [
699
+ {
700
+ action: "setLineItemCustomField",
701
+ lineItemId: lineItem.id,
702
+ name: "foo",
703
+ value: "bar",
704
+ },
705
+ ],
706
+ });
707
+
708
+ expect(response.status).toBe(200);
709
+ expect(response.body.version).toBe(2);
710
+ expect(response.body.lineItems).toMatchObject([
711
+ {
712
+ id: lineItem.id,
713
+ custom: {
714
+ fields: {
715
+ foo: "bar",
716
+ },
717
+ },
718
+ },
719
+ ]);
720
+ });
721
+
722
+ test("setLineItemCustomType", async () => {
723
+ const order: Order = {
724
+ ...getBaseResourceProperties(),
725
+ version: 1,
726
+ customLineItems: [],
727
+ directDiscounts: [],
728
+ discountCodes: [],
729
+ lineItems: [
730
+ {
731
+ id: "d70b14c8-72cf-4cab-82ba-6339cebe1e79",
732
+ productId: "06028a97-d622-47ac-a194-a3d90baa2b3c",
733
+ productSlug: { "nl-NL": "test-product" },
734
+ productType: { typeId: "product-type", id: "some-uuid" },
735
+ name: { "nl-NL": "test product" },
736
+ variant: {
737
+ id: 1,
738
+ sku: "1337",
739
+ attributes: [{ name: "test", value: "test" }],
740
+ prices: [],
741
+ assets: [],
742
+ images: [],
743
+ },
744
+ price: {
745
+ id: "2f59a6c9-6a86-48d3-87f9-fabb3b12fd93",
746
+ value: {
747
+ type: "centPrecision",
748
+ centAmount: 14900,
749
+ currencyCode: "EUR",
750
+ fractionDigits: 2,
751
+ },
752
+ },
753
+ totalPrice: {
754
+ type: "centPrecision",
755
+ currencyCode: "EUR",
756
+ fractionDigits: 2,
757
+ centAmount: 14900,
758
+ },
759
+ taxedPricePortions: [],
760
+ perMethodTaxRate: [],
761
+ quantity: 1,
762
+ discountedPricePerQuantity: [],
763
+ lineItemMode: "Standard",
764
+ priceMode: "Platform",
765
+ state: [],
766
+ },
767
+ ],
768
+ orderState: "Open",
769
+ origin: "Customer",
770
+ refusedGifts: [],
771
+ shipping: [],
772
+ shippingMode: "Single",
773
+ syncInfo: [],
774
+ taxCalculationMode: "LineItemLevel",
775
+ taxMode: "Platform",
776
+ taxRoundingMode: "HalfEven",
777
+ totalPrice: {
778
+ type: "centPrecision",
779
+ centAmount: 14900,
780
+ currencyCode: "EUR",
781
+ fractionDigits: 0,
782
+ },
783
+ };
784
+
785
+ ctMock.project("dummy").add("order", order);
786
+
787
+ const type = await supertest(ctMock.app)
788
+ .post("/dummy/types")
789
+ .send({
790
+ key: "my-type",
791
+ name: {
792
+ en: "My Type",
793
+ },
794
+ description: {
795
+ en: "My Type Description",
796
+ },
797
+ fieldDefinitions: [
798
+ {
799
+ name: "foo",
800
+ label: {
801
+ en: "foo",
802
+ },
803
+ required: false,
804
+ type: {
805
+ name: "String",
806
+ },
807
+ inputHint: "SingleLine",
808
+ },
809
+ ],
810
+ })
811
+ .then((x) => x.body);
812
+
813
+ assert(type, "type not created");
814
+
815
+ const lineItem = order.lineItems[0];
816
+ assert(lineItem, "lineItem not created");
817
+
818
+ const response = await supertest(ctMock.app)
819
+ .post(`/dummy/orders/${order.id}`)
820
+ .send({
821
+ version: order.version,
822
+ actions: [
823
+ {
824
+ action: "setLineItemCustomType",
825
+ lineItemId: lineItem.id,
826
+ type: {
827
+ typeId: "type",
828
+ id: type.id,
829
+ },
830
+ },
831
+ ],
832
+ });
833
+
834
+ expect(response.status).toBe(200);
835
+ expect(response.body.version).toBe(2);
836
+ expect(response.body.lineItems).toMatchObject([
837
+ {
838
+ id: lineItem.id,
839
+ custom: {
840
+ type: {
841
+ typeId: "type",
842
+ id: type.id,
843
+ },
844
+ },
845
+ },
846
+ ]);
847
+ });
848
+
614
849
  test("setParcelCustomField", async () => {
615
850
  const order: Order = {
616
851
  ...getBaseResourceProperties(),