@labdigital/commercetools-mock 2.57.1 → 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.57.1",
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"
@@ -2,10 +2,6 @@ import type {
2
2
  CartSetAnonymousIdAction,
3
3
  CartSetCustomerIdAction,
4
4
  CartUpdateAction,
5
- CentPrecisionMoney,
6
- InvalidOperationError,
7
- MissingTaxRateForCountryError,
8
- ShippingMethodDoesNotMatchCartError,
9
5
  } from "@commercetools/platform-sdk";
10
6
  import type {
11
7
  Address,
@@ -30,6 +26,8 @@ import type {
30
26
  CartSetCustomTypeAction,
31
27
  CartSetCustomerEmailAction,
32
28
  CartSetDirectDiscountsAction,
29
+ CartSetLineItemCustomFieldAction,
30
+ CartSetLineItemCustomTypeAction,
33
31
  CartSetLineItemShippingDetailsAction,
34
32
  CartSetLocaleAction,
35
33
  CartSetShippingAddressAction,
@@ -48,15 +46,12 @@ import type {
48
46
  import type {
49
47
  CustomLineItem,
50
48
  DirectDiscount,
51
- TaxPortion,
52
- TaxedItemPrice,
53
49
  } from "@commercetools/platform-sdk/dist/declarations/src/generated/models/cart";
54
50
  import type { ShippingMethodResourceIdentifier } from "@commercetools/platform-sdk/dist/declarations/src/generated/models/shipping-method";
55
- import { Decimal } from "decimal.js/decimal";
56
51
  import { v4 as uuidv4 } from "uuid";
57
52
  import { CommercetoolsError } from "~src/exceptions";
58
- import { getShippingMethodsMatchingCart } from "~src/shipping";
59
53
  import type { Writable } from "~src/types";
54
+ import type { CartRepository } from ".";
60
55
  import type { UpdateHandlerInterface } from "../abstract";
61
56
  import { AbstractUpdateHandler, type RepositoryContext } from "../abstract";
62
57
  import {
@@ -64,13 +59,10 @@ import {
64
59
  createCentPrecisionMoney,
65
60
  createCustomFields,
66
61
  createTypedMoney,
67
- getReferenceFromResourceIdentifier,
68
- roundDecimal,
69
62
  } from "../helpers";
70
63
  import {
71
64
  calculateCartTotalPrice,
72
65
  calculateLineItemTotalPrice,
73
- calculateTaxedPrice,
74
66
  createCustomLineItemFromDraft,
75
67
  selectPrice,
76
68
  } from "./helpers";
@@ -79,6 +71,12 @@ export class CartUpdateHandler
79
71
  extends AbstractUpdateHandler
80
72
  implements Partial<UpdateHandlerInterface<Cart, CartUpdateAction>>
81
73
  {
74
+ private repository: CartRepository;
75
+
76
+ constructor(storage: any, repository: CartRepository) {
77
+ super(storage);
78
+ this.repository = repository;
79
+ }
82
80
  addItemShippingAddress(
83
81
  context: RepositoryContext,
84
82
  resource: Writable<Cart>,
@@ -666,6 +664,82 @@ export class CartUpdateHandler
666
664
  );
667
665
  }
668
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
+
669
743
  setLineItemShippingDetails(
670
744
  context: RepositoryContext,
671
745
  resource: Writable<Cart>,
@@ -769,166 +843,11 @@ export class CartUpdateHandler
769
843
  { shippingMethod }: CartSetShippingMethodAction,
770
844
  ) {
771
845
  if (shippingMethod) {
772
- if (resource.taxMode === "External") {
773
- throw new Error("External tax rate is not supported");
774
- }
775
-
776
- const country = resource.shippingAddress?.country;
777
-
778
- if (!country) {
779
- throw new CommercetoolsError<InvalidOperationError>({
780
- code: "InvalidOperation",
781
- message: `The cart with ID '${resource.id}' does not have a shipping address set.`,
782
- });
783
- }
784
-
785
- // Bit of a hack: calling this checks that the resource identifier is
786
- // valid (i.e. id xor key) and that the shipping method exists.
787
- this._storage.getByResourceIdentifier<"shipping-method">(
788
- context.projectKey,
789
- shippingMethod,
790
- );
791
-
792
- // getShippingMethodsMatchingCart does the work of determining whether the
793
- // shipping method is allowed for the cart, and which shipping rate to use
794
- const shippingMethods = getShippingMethodsMatchingCart(
846
+ resource.shippingInfo = this.repository.createShippingInfo(
795
847
  context,
796
- this._storage,
797
848
  resource,
798
- {
799
- expand: ["zoneRates[*].zone"],
800
- },
801
- );
802
-
803
- const method = shippingMethods.results.find((candidate) =>
804
- shippingMethod.id
805
- ? candidate.id === shippingMethod.id
806
- : candidate.key === shippingMethod.key,
807
- );
808
-
809
- // Not finding the method in the results means it's not allowed, since
810
- // getShippingMethodsMatchingCart only returns allowed methods and we
811
- // already checked that the method exists.
812
- if (!method) {
813
- throw new CommercetoolsError<ShippingMethodDoesNotMatchCartError>({
814
- code: "ShippingMethodDoesNotMatchCart",
815
- message: `The shipping method with ${shippingMethod.id ? `ID '${shippingMethod.id}'` : `key '${shippingMethod.key}'`} is not allowed for the cart with ID '${resource.id}'.`,
816
- });
817
- }
818
-
819
- const taxCategory = this._storage.getByResourceIdentifier<"tax-category">(
820
- context.projectKey,
821
- method.taxCategory,
822
- );
823
-
824
- // TODO: match state in addition to country
825
- const taxRate = taxCategory.rates.find(
826
- (rate) => rate.country === country,
827
- );
828
-
829
- if (!taxRate) {
830
- throw new CommercetoolsError<MissingTaxRateForCountryError>({
831
- code: "MissingTaxRateForCountry",
832
- message: `Tax category '${taxCategory.id}' is missing a tax rate for country '${country}'.`,
833
- taxCategoryId: taxCategory.id,
834
- });
835
- }
836
-
837
- // There should only be one zone rate matching the address, since
838
- // Locations cannot be assigned to more than one zone.
839
- // See https://docs.commercetools.com/api/projects/zones#location
840
- const zoneRate = method.zoneRates.find((rate) =>
841
- rate.zone.obj?.locations.some((loc) => loc.country === country),
842
- );
843
-
844
- if (!zoneRate) {
845
- // This shouldn't happen because getShippingMethodsMatchingCart already
846
- // filtered out shipping methods without any zones matching the address
847
- throw new Error("Zone rate not found");
848
- }
849
-
850
- // Shipping rates are defined by currency, and getShippingMethodsMatchingCart
851
- // also matches on currency, so there should only be one in the array.
852
- // See https://docs.commercetools.com/api/projects/shippingMethods#zonerate
853
- const shippingRate = zoneRate.shippingRates[0];
854
- if (!shippingRate) {
855
- // This shouldn't happen because getShippingMethodsMatchingCart already
856
- // filtered out shipping methods without any matching rates
857
- throw new Error("Shipping rate not found");
858
- }
859
-
860
- const shippingRateTier = shippingRate.tiers.find(
861
- (tier) => tier.isMatching,
849
+ shippingMethod,
862
850
  );
863
- if (shippingRateTier && shippingRateTier.type !== "CartValue") {
864
- throw new Error("Non-CartValue shipping rate tier is not supported");
865
- }
866
-
867
- const shippingPrice = shippingRateTier
868
- ? createCentPrecisionMoney(shippingRateTier.price)
869
- : shippingRate.price;
870
-
871
- // TODO: handle freeAbove
872
-
873
- const totalGross: CentPrecisionMoney = taxRate.includedInPrice
874
- ? shippingPrice
875
- : {
876
- ...shippingPrice,
877
- centAmount: roundDecimal(
878
- new Decimal(shippingPrice.centAmount).mul(1 + taxRate.amount),
879
- resource.taxRoundingMode,
880
- ).toNumber(),
881
- };
882
-
883
- const totalNet: CentPrecisionMoney = taxRate.includedInPrice
884
- ? {
885
- ...shippingPrice,
886
- centAmount: roundDecimal(
887
- new Decimal(shippingPrice.centAmount).div(1 + taxRate.amount),
888
- resource.taxRoundingMode,
889
- ).toNumber(),
890
- }
891
- : shippingPrice;
892
-
893
- const taxPortions: TaxPortion[] = [
894
- {
895
- name: taxRate.name,
896
- rate: taxRate.amount,
897
- amount: {
898
- ...shippingPrice,
899
- centAmount: totalGross.centAmount - totalNet.centAmount,
900
- },
901
- },
902
- ];
903
-
904
- const totalTax: CentPrecisionMoney = {
905
- ...shippingPrice,
906
- centAmount: taxPortions.reduce(
907
- (acc, portion) => acc + portion.amount.centAmount,
908
- 0,
909
- ),
910
- };
911
-
912
- const taxedPrice: TaxedItemPrice = {
913
- totalNet,
914
- totalGross,
915
- taxPortions,
916
- totalTax,
917
- };
918
-
919
- // @ts-ignore
920
- resource.shippingInfo = {
921
- shippingMethod: {
922
- typeId: "shipping-method",
923
- id: method.id,
924
- },
925
- shippingMethodName: method.name,
926
- price: shippingPrice,
927
- shippingRate,
928
- taxedPrice,
929
- taxRate,
930
- taxCategory: method.taxCategory,
931
- };
932
851
  } else {
933
852
  resource.shippingInfo = undefined;
934
853
  }