@labdigital/commercetools-mock 2.46.0 → 2.47.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.
Files changed (79) hide show
  1. package/dist/index.cjs +568 -241
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +782 -58
  4. package/dist/index.d.ts +782 -58
  5. package/dist/index.js +556 -229
  6. package/dist/index.js.map +1 -1
  7. package/package.json +41 -48
  8. package/src/ctMock.ts +11 -13
  9. package/src/index.test.ts +5 -5
  10. package/src/lib/predicateParser.test.ts +62 -62
  11. package/src/lib/predicateParser.ts +32 -42
  12. package/src/lib/productSearchFilter.test.ts +18 -0
  13. package/src/lib/productSearchFilter.ts +7 -0
  14. package/src/lib/projectionSearchFilter.test.ts +17 -17
  15. package/src/lib/projectionSearchFilter.ts +2 -3
  16. package/src/oauth/server.test.ts +1 -1
  17. package/src/oauth/server.ts +11 -11
  18. package/src/priceSelector.ts +1 -1
  19. package/src/product-projection-search.ts +18 -19
  20. package/src/repositories/business-unit.ts +17 -16
  21. package/src/repositories/cart/actions.ts +32 -32
  22. package/src/repositories/cart/helpers.ts +1 -1
  23. package/src/repositories/cart/index.ts +8 -8
  24. package/src/repositories/cart-discount/actions.ts +1 -4
  25. package/src/repositories/category/actions.ts +2 -6
  26. package/src/repositories/custom-object.ts +20 -21
  27. package/src/repositories/customer/actions.ts +4 -4
  28. package/src/repositories/errors.ts +1 -1
  29. package/src/repositories/extension.ts +2 -1
  30. package/src/repositories/helpers.ts +27 -27
  31. package/src/repositories/index.ts +17 -17
  32. package/src/repositories/my-customer.ts +1 -1
  33. package/src/repositories/my-order.ts +2 -2
  34. package/src/repositories/order/index.ts +1 -1
  35. package/src/repositories/product/actions.ts +1 -1
  36. package/src/repositories/quote/actions.ts +83 -0
  37. package/src/repositories/quote/index.ts +54 -0
  38. package/src/repositories/quote-request/actions.ts +84 -0
  39. package/src/repositories/quote-request/index.test.ts +167 -0
  40. package/src/repositories/quote-request/index.ts +67 -0
  41. package/src/repositories/quote-staged/actions.ts +84 -0
  42. package/src/repositories/quote-staged/index.ts +47 -0
  43. package/src/repositories/review.ts +4 -4
  44. package/src/repositories/shipping-method/actions.ts +17 -17
  45. package/src/repositories/shipping-method/index.ts +6 -6
  46. package/src/repositories/shopping-list/actions.ts +1 -1
  47. package/src/repositories/shopping-list/index.ts +9 -1
  48. package/src/repositories/subscription.ts +2 -4
  49. package/src/server.ts +3 -2
  50. package/src/services/abstract.ts +7 -7
  51. package/src/services/as-associate-order.test.ts +1 -1
  52. package/src/services/cart-discount.test.ts +1 -1
  53. package/src/services/cart.test.ts +15 -15
  54. package/src/services/category.test.ts +1 -1
  55. package/src/services/customer.test.ts +4 -4
  56. package/src/services/customer.ts +1 -1
  57. package/src/services/index.ts +20 -14
  58. package/src/services/inventory-entry.test.ts +5 -5
  59. package/src/services/my-cart.test.ts +2 -2
  60. package/src/services/my-customer.test.ts +2 -2
  61. package/src/services/order.test.ts +8 -8
  62. package/src/services/product-projection.test.ts +5 -5
  63. package/src/services/product-projection.ts +12 -14
  64. package/src/services/product.test.ts +1 -1
  65. package/src/services/quote-request.test.ts +59 -0
  66. package/src/services/quote-request.ts +16 -0
  67. package/src/services/quote-staged.ts +16 -0
  68. package/src/services/quote.ts +16 -0
  69. package/src/services/standalone-price.test.ts +4 -4
  70. package/src/services/state.test.ts +1 -1
  71. package/src/services/store.test.ts +2 -2
  72. package/src/services/tax-category.test.ts +1 -1
  73. package/src/shipping.ts +3 -3
  74. package/src/storage/in-memory.ts +55 -63
  75. package/src/testing/customer.ts +1 -1
  76. package/src/types.ts +51 -31
  77. package/src/repositories/quote-request.ts +0 -17
  78. package/src/repositories/quote.ts +0 -14
  79. package/src/repositories/staged-quote.ts +0 -17
@@ -30,10 +30,10 @@ import { ProductTypeRepository } from "./product-type";
30
30
  import { ProjectRepository } from "./project";
31
31
  import { QuoteRepository } from "./quote";
32
32
  import { QuoteRequestRepository } from "./quote-request";
33
+ import { StagedQuoteRepository } from "./quote-staged";
33
34
  import { ReviewRepository } from "./review";
34
35
  import { ShippingMethodRepository } from "./shipping-method";
35
36
  import { ShoppingListRepository } from "./shopping-list";
36
- import { StagedQuoteRepository } from "./staged-quote";
37
37
  import { StandAlonePriceRepository } from "./standalone-price";
38
38
  import { StateRepository } from "./state";
39
39
  import { StoreRepository } from "./store";
@@ -52,42 +52,42 @@ export const createRepositories = (config: Config) => ({
52
52
  "associate-role": new AssociateRoleRepository(config),
53
53
  "attribute-group": new AttributeGroupRepository(config),
54
54
  "business-unit": new BusinessUnitRepository(config),
55
- "category": new CategoryRepository(config),
56
- "cart": new CartRepository(config),
55
+ category: new CategoryRepository(config),
56
+ cart: new CartRepository(config),
57
57
  "cart-discount": new CartDiscountRepository(config),
58
- "customer": new CustomerRepository(config),
59
- "channel": new ChannelRepository(config),
58
+ customer: new CustomerRepository(config),
59
+ channel: new ChannelRepository(config),
60
60
  "customer-group": new CustomerGroupRepository(config),
61
61
  "discount-code": new DiscountCodeRepository(config),
62
- "extension": new ExtensionRepository(config),
62
+ extension: new ExtensionRepository(config),
63
63
  "inventory-entry": new InventoryEntryRepository(config),
64
64
  "key-value-document": new CustomObjectRepository(config),
65
- "order": new OrderRepository(config),
65
+ order: new OrderRepository(config),
66
66
  "order-edit": new OrderEditRepository(config),
67
- "payment": new PaymentRepository(config),
67
+ payment: new PaymentRepository(config),
68
68
  "my-cart": new CartRepository(config),
69
69
  "my-order": new MyOrderRepository(config),
70
70
  "my-customer": new MyCustomerRepository(config),
71
71
  "my-payment": new PaymentRepository(config),
72
72
  "my-shopping-list": new ShoppingListRepository(config),
73
- "product": new ProductRepository(config),
73
+ product: new ProductRepository(config),
74
74
  "product-type": new ProductTypeRepository(config),
75
75
  "product-discount": new ProductDiscountRepository(config),
76
76
  "product-projection": new ProductProjectionRepository(config),
77
77
  "product-selection": new ProductSelectionRepository(config),
78
78
  "product-tailoring": new ProductTailoringRepository(config),
79
- "project": new ProjectRepository(config),
80
- "review": new ReviewRepository(config),
81
- "quote": new QuoteRepository(config),
79
+ project: new ProjectRepository(config),
80
+ review: new ReviewRepository(config),
81
+ quote: new QuoteRepository(config),
82
82
  "quote-request": new QuoteRequestRepository(config),
83
83
  "shipping-method": new ShippingMethodRepository(config),
84
84
  "shopping-list": new ShoppingListRepository(config),
85
85
  "staged-quote": new StagedQuoteRepository(config),
86
86
  "standalone-price": new StandAlonePriceRepository(config),
87
- "state": new StateRepository(config),
88
- "store": new StoreRepository(config),
89
- "subscription": new SubscriptionRepository(config),
87
+ state: new StateRepository(config),
88
+ store: new StoreRepository(config),
89
+ subscription: new SubscriptionRepository(config),
90
90
  "tax-category": new TaxCategoryRepository(config),
91
- "type": new TypeRepository(config),
92
- "zone": new ZoneRepository(config),
91
+ type: new TypeRepository(config),
92
+ zone: new ZoneRepository(config),
93
93
  });
@@ -8,7 +8,7 @@ import type {
8
8
  import { CommercetoolsError } from "~src/exceptions";
9
9
  import { hashPassword, validateEmailVerifyToken } from "../lib/password";
10
10
  import type { Writable } from "../types";
11
- import { type RepositoryContext } from "./abstract";
11
+ import type { RepositoryContext } from "./abstract";
12
12
  import { CustomerRepository } from "./customer";
13
13
 
14
14
  export class MyCustomerRepository extends CustomerRepository {
@@ -1,10 +1,10 @@
1
+ import assert from "node:assert";
1
2
  import type {
2
3
  CartReference,
3
4
  MyOrderFromCartDraft,
4
5
  Order,
5
6
  } from "@commercetools/platform-sdk";
6
- import assert from "assert";
7
- import { type RepositoryContext } from "./abstract";
7
+ import type { RepositoryContext } from "./abstract";
8
8
  import { OrderRepository } from "./order";
9
9
 
10
10
  export class MyOrderRepository extends OrderRepository {
@@ -1,3 +1,4 @@
1
+ import assert from "node:assert";
1
2
  import type {
2
3
  Cart,
3
4
  CartReference,
@@ -13,7 +14,6 @@ import type {
13
14
  ProductPagedQueryResponse,
14
15
  ProductVariant,
15
16
  } from "@commercetools/platform-sdk";
16
- import assert from "assert";
17
17
  import type { Config } from "~src/config";
18
18
  import { CommercetoolsError } from "~src/exceptions";
19
19
  import { generateRandomString, getBaseResourceProperties } from "~src/helpers";
@@ -420,7 +420,7 @@ export class ProductUpdateHandler
420
420
 
421
421
  if (position >= variantImages.length) {
422
422
  throw new Error(
423
- `Invalid position given. Position in images where the image should be moved. Must be between 0 and the total number of images minus 1.`,
423
+ "Invalid position given. Position in images where the image should be moved. Must be between 0 and the total number of images minus 1.",
424
424
  );
425
425
  }
426
426
 
@@ -0,0 +1,83 @@
1
+ import type {
2
+ InvalidJsonInputError,
3
+ Quote,
4
+ QuoteSetCustomFieldAction,
5
+ QuoteSetCustomTypeAction,
6
+ QuoteTransitionStateAction,
7
+ QuoteUpdateAction,
8
+ StateReference,
9
+ } from "@commercetools/platform-sdk";
10
+ import { CommercetoolsError } from "~src/exceptions";
11
+ import type { Writable } from "~src/types";
12
+ import type { RepositoryContext, UpdateHandlerInterface } from "../abstract";
13
+ import { AbstractUpdateHandler } from "../abstract";
14
+ import { getReferenceFromResourceIdentifier } from "../helpers";
15
+
16
+ export class QuoteUpdateHandler
17
+ extends AbstractUpdateHandler
18
+ implements Partial<UpdateHandlerInterface<Quote, QuoteUpdateAction>>
19
+ {
20
+ setCustomField(
21
+ context: RepositoryContext,
22
+ resource: Quote,
23
+ { name, value }: QuoteSetCustomFieldAction,
24
+ ) {
25
+ if (!resource.custom) {
26
+ throw new Error("Resource has no custom field");
27
+ }
28
+ resource.custom.fields[name] = value;
29
+ }
30
+
31
+ setCustomType(
32
+ context: RepositoryContext,
33
+ resource: Writable<Quote>,
34
+ { type, fields }: QuoteSetCustomTypeAction,
35
+ ) {
36
+ if (!type) {
37
+ resource.custom = undefined;
38
+ } else {
39
+ const resolvedType = this._storage.getByResourceIdentifier(
40
+ context.projectKey,
41
+ type,
42
+ );
43
+ if (!resolvedType) {
44
+ throw new Error(`Type ${type} not found`);
45
+ }
46
+
47
+ resource.custom = {
48
+ type: {
49
+ typeId: "type",
50
+ id: resolvedType.id,
51
+ },
52
+ fields: fields || {},
53
+ };
54
+ }
55
+ }
56
+
57
+ transitionState(
58
+ context: RepositoryContext,
59
+ resource: Writable<Quote>,
60
+ { state, force }: QuoteTransitionStateAction,
61
+ ) {
62
+ let stateReference: StateReference | undefined = undefined;
63
+ if (state) {
64
+ stateReference = getReferenceFromResourceIdentifier<StateReference>(
65
+ state,
66
+ context.projectKey,
67
+ this._storage,
68
+ );
69
+ resource.state = stateReference;
70
+ } else {
71
+ throw new CommercetoolsError<InvalidJsonInputError>(
72
+ {
73
+ code: "InvalidJsonInput",
74
+ message: "Request body does not contain valid JSON.",
75
+ detailedErrorMessage: "actions -> state: Missing required value",
76
+ },
77
+ 400,
78
+ );
79
+ }
80
+
81
+ return resource;
82
+ }
83
+ }
@@ -0,0 +1,54 @@
1
+ import type { Quote, QuoteDraft } from "@commercetools/platform-sdk";
2
+ import type { Config } from "~src/config";
3
+ import { getBaseResourceProperties } from "~src/helpers";
4
+ import type { RepositoryContext } from "../abstract";
5
+ import { AbstractResourceRepository } from "../abstract";
6
+ import { QuoteUpdateHandler } from "./actions";
7
+
8
+ export class QuoteRepository extends AbstractResourceRepository<"quote"> {
9
+ constructor(config: Config) {
10
+ super("quote", config);
11
+ this.actions = new QuoteUpdateHandler(config.storage);
12
+ }
13
+
14
+ create(context: RepositoryContext, draft: QuoteDraft): Quote {
15
+ const staged = this._storage.getByResourceIdentifier<"staged-quote">(
16
+ context.projectKey,
17
+ draft.stagedQuote,
18
+ );
19
+
20
+ const cart = this._storage.getByResourceIdentifier<"cart">(
21
+ context.projectKey,
22
+ staged.quotationCart,
23
+ );
24
+
25
+ if (!cart.customerId) {
26
+ throw new Error("Cart does not have a customer");
27
+ }
28
+
29
+ const resource: Quote = {
30
+ ...getBaseResourceProperties(),
31
+ quoteState: "Accepted",
32
+ quoteRequest: staged.quoteRequest,
33
+ lineItems: cart.lineItems,
34
+ customLineItems: cart.customLineItems,
35
+ customer: {
36
+ typeId: "customer",
37
+ id: cart.customerId,
38
+ },
39
+ stagedQuote: {
40
+ typeId: "staged-quote",
41
+ id: staged.id,
42
+ },
43
+ totalPrice: cart.totalPrice,
44
+ taxedPrice: cart.taxedPrice,
45
+ taxMode: cart.taxMode,
46
+ taxRoundingMode: cart.taxRoundingMode,
47
+ taxCalculationMode: cart.taxCalculationMode,
48
+ billingAddress: cart.billingAddress,
49
+ shippingAddress: cart.shippingAddress,
50
+ };
51
+
52
+ return resource;
53
+ }
54
+ }
@@ -0,0 +1,84 @@
1
+ import type {
2
+ InvalidJsonInputError,
3
+ QuoteRequest,
4
+ QuoteRequestSetCustomFieldAction,
5
+ QuoteRequestSetCustomTypeAction,
6
+ QuoteRequestTransitionStateAction,
7
+ QuoteRequestUpdateAction,
8
+ StateReference,
9
+ } from "@commercetools/platform-sdk";
10
+ import { CommercetoolsError } from "~src/exceptions";
11
+ import type { Writable } from "~src/types";
12
+ import type { RepositoryContext, UpdateHandlerInterface } from "../abstract";
13
+ import { AbstractUpdateHandler } from "../abstract";
14
+ import { getReferenceFromResourceIdentifier } from "../helpers";
15
+
16
+ export class QuoteRequestUpdateHandler
17
+ extends AbstractUpdateHandler
18
+ implements
19
+ Partial<UpdateHandlerInterface<QuoteRequest, QuoteRequestUpdateAction>>
20
+ {
21
+ setCustomField(
22
+ context: RepositoryContext,
23
+ resource: QuoteRequest,
24
+ { name, value }: QuoteRequestSetCustomFieldAction,
25
+ ) {
26
+ if (!resource.custom) {
27
+ throw new Error("Resource has no custom field");
28
+ }
29
+ resource.custom.fields[name] = value;
30
+ }
31
+
32
+ setCustomType(
33
+ context: RepositoryContext,
34
+ resource: Writable<QuoteRequest>,
35
+ { type, fields }: QuoteRequestSetCustomTypeAction,
36
+ ) {
37
+ if (!type) {
38
+ resource.custom = undefined;
39
+ } else {
40
+ const resolvedType = this._storage.getByResourceIdentifier(
41
+ context.projectKey,
42
+ type,
43
+ );
44
+ if (!resolvedType) {
45
+ throw new Error(`Type ${type} not found`);
46
+ }
47
+
48
+ resource.custom = {
49
+ type: {
50
+ typeId: "type",
51
+ id: resolvedType.id,
52
+ },
53
+ fields: fields || {},
54
+ };
55
+ }
56
+ }
57
+
58
+ transitionState(
59
+ context: RepositoryContext,
60
+ resource: Writable<QuoteRequest>,
61
+ { state, force }: QuoteRequestTransitionStateAction,
62
+ ) {
63
+ let stateReference: StateReference | undefined = undefined;
64
+ if (state) {
65
+ stateReference = getReferenceFromResourceIdentifier<StateReference>(
66
+ state,
67
+ context.projectKey,
68
+ this._storage,
69
+ );
70
+ resource.state = stateReference;
71
+ } else {
72
+ throw new CommercetoolsError<InvalidJsonInputError>(
73
+ {
74
+ code: "InvalidJsonInput",
75
+ message: "Request body does not contain valid JSON.",
76
+ detailedErrorMessage: "actions -> state: Missing required value",
77
+ },
78
+ 400,
79
+ );
80
+ }
81
+
82
+ return resource;
83
+ }
84
+ }
@@ -0,0 +1,167 @@
1
+ import type { Cart, LineItem } from "@commercetools/platform-sdk";
2
+ import { describe, expect, test } from "vitest";
3
+ import type { Config } from "~src/config";
4
+ import { InMemoryStorage } from "~src/storage";
5
+ import { QuoteRequestRepository } from ".";
6
+
7
+ describe("QuoteRequest repository", () => {
8
+ const storage = new InMemoryStorage();
9
+ const config: Config = {
10
+ storage,
11
+ strict: false,
12
+ };
13
+ const repository = new QuoteRequestRepository(config);
14
+
15
+ test("create from cart", async () => {
16
+ const cart: Cart = {
17
+ id: "b3875a58-4ab2-4aaa-b399-184ce7561c27",
18
+ version: 1,
19
+ createdAt: "2021-09-02T12:23:30.036Z",
20
+ lastModifiedAt: "2021-09-02T12:23:30.546Z",
21
+ discountCodes: [],
22
+ directDiscounts: [],
23
+ inventoryMode: "None",
24
+ itemShippingAddresses: [],
25
+ lineItems: [
26
+ {
27
+ id: "15fc56ba-a74e-4cf8-b4b0-bada5c101541",
28
+ productId: "PRODUCTID",
29
+ variantId: 1,
30
+ quantity: 1,
31
+ } as unknown as LineItem,
32
+ ],
33
+ customLineItems: [],
34
+ totalPrice: {
35
+ type: "centPrecision",
36
+ currencyCode: "EUR",
37
+ centAmount: 10000,
38
+ fractionDigits: 2,
39
+ },
40
+ cartState: "Active",
41
+ shippingMode: "Single",
42
+ shipping: [],
43
+ taxMode: "Platform",
44
+ taxRoundingMode: "HalfEven",
45
+ taxCalculationMode: "UnitPriceLevel",
46
+ refusedGifts: [],
47
+ origin: "Customer",
48
+ anonymousId: "1234567890",
49
+ billingAddress: {
50
+ id: "1234567890",
51
+ country: "NL",
52
+ firstName: "John",
53
+ lastName: "Doe",
54
+ streetName: "Main Street",
55
+ streetNumber: "123",
56
+ postalCode: "123456",
57
+ },
58
+ customerEmail: "john.doe@example.com",
59
+ customerGroup: {
60
+ id: "1234567890",
61
+ typeId: "customer-group",
62
+ },
63
+ customerId: "1234567890",
64
+ custom: {
65
+ type: {
66
+ typeId: "type",
67
+ id: "1234567890",
68
+ },
69
+ fields: {
70
+ description: "example description",
71
+ },
72
+ },
73
+
74
+ shippingAddress: {
75
+ id: "1234567890",
76
+ country: "NL",
77
+ firstName: "John",
78
+ lastName: "Doe",
79
+ streetName: "Main Street",
80
+ streetNumber: "123",
81
+ postalCode: "123456",
82
+ },
83
+ shippingInfo: {
84
+ shippingMethodName: "Standard Shipping",
85
+ price: {
86
+ type: "centPrecision",
87
+ currencyCode: "EUR",
88
+ centAmount: 1000,
89
+ fractionDigits: 2,
90
+ },
91
+ shippingRate: {
92
+ price: {
93
+ type: "centPrecision",
94
+ currencyCode: "EUR",
95
+ centAmount: 1000,
96
+ fractionDigits: 2,
97
+ },
98
+ tiers: [],
99
+ },
100
+ shippingMethodState: "Shipped",
101
+ },
102
+ taxedPrice: {
103
+ totalNet: {
104
+ type: "centPrecision",
105
+ currencyCode: "EUR",
106
+ centAmount: 1000,
107
+ fractionDigits: 2,
108
+ },
109
+ taxPortions: [],
110
+ totalGross: {
111
+ type: "centPrecision",
112
+ currencyCode: "EUR",
113
+ centAmount: 1210,
114
+ fractionDigits: 2,
115
+ },
116
+ },
117
+ taxedShippingPrice: {
118
+ totalNet: {
119
+ type: "centPrecision",
120
+ currencyCode: "EUR",
121
+ centAmount: 100,
122
+ fractionDigits: 2,
123
+ },
124
+ taxPortions: [],
125
+ totalGross: {
126
+ type: "centPrecision",
127
+ currencyCode: "EUR",
128
+ centAmount: 121,
129
+ fractionDigits: 2,
130
+ },
131
+ },
132
+ };
133
+
134
+ storage.add("dummy", "cart", cart);
135
+ const ctx = { projectKey: "dummy" };
136
+
137
+ const result = repository.create(ctx, {
138
+ cart: {
139
+ id: cart.id,
140
+ typeId: "cart",
141
+ },
142
+ cartVersion: cart.version,
143
+ });
144
+ expect(result.cart?.id).toBe(cart.id);
145
+
146
+ const items = repository.query(ctx);
147
+ expect(items.count).toBe(1);
148
+
149
+ expect(result.billingAddress).toEqual(cart.billingAddress);
150
+ expect(result.cart?.id).toEqual(cart.id);
151
+ expect(result.country).toEqual(cart.country);
152
+ expect(result.custom).toEqual(cart.custom);
153
+ expect(result.customerGroup).toEqual(cart.customerGroup);
154
+ expect(result.customer.id).toEqual(cart.customerId);
155
+ expect(result.customLineItems).toEqual(cart.customLineItems);
156
+ expect(result.directDiscounts).toEqual(cart.directDiscounts);
157
+ expect(result.lineItems).toEqual(cart.lineItems);
158
+ expect(result.paymentInfo).toEqual(cart.paymentInfo);
159
+ expect(result.shippingAddress).toEqual(cart.shippingAddress);
160
+ expect(result.taxCalculationMode).toEqual(cart.taxCalculationMode);
161
+ expect(result.taxedPrice).toEqual(cart.taxedPrice);
162
+ expect(result.taxMode).toEqual(cart.taxMode);
163
+ expect(result.taxRoundingMode).toEqual(cart.taxRoundingMode);
164
+ expect(result.totalPrice).toEqual(cart.totalPrice);
165
+ expect(result.store).toEqual(cart.store);
166
+ });
167
+ });
@@ -0,0 +1,67 @@
1
+ import assert from "node:assert";
2
+ import type {
3
+ Cart,
4
+ CartReference,
5
+ QuoteRequest,
6
+ QuoteRequestDraft,
7
+ } from "@commercetools/platform-sdk";
8
+ import type { Config } from "~src/config";
9
+ import { getBaseResourceProperties } from "~src/helpers";
10
+ import type { RepositoryContext } from "../abstract";
11
+ import { AbstractResourceRepository } from "../abstract";
12
+ import { QuoteRequestUpdateHandler } from "./actions";
13
+
14
+ export class QuoteRequestRepository extends AbstractResourceRepository<"quote-request"> {
15
+ constructor(config: Config) {
16
+ super("quote-request", config);
17
+ this.actions = new QuoteRequestUpdateHandler(config.storage);
18
+ }
19
+
20
+ create(context: RepositoryContext, draft: QuoteRequestDraft): QuoteRequest {
21
+ assert(draft.cart, "draft.cart is missing");
22
+ return this.createFromCart(context, {
23
+ id: draft.cart.id!,
24
+ typeId: "cart",
25
+ });
26
+ }
27
+
28
+ createFromCart(context: RepositoryContext, cartReference: CartReference) {
29
+ const cart = this._storage.getByResourceIdentifier(
30
+ context.projectKey,
31
+ cartReference,
32
+ ) as Cart | null;
33
+ if (!cart) {
34
+ throw new Error("Cannot find cart");
35
+ }
36
+
37
+ if (!cart.customerId) {
38
+ throw new Error("Cart does not have a customer");
39
+ }
40
+
41
+ const resource: QuoteRequest = {
42
+ ...getBaseResourceProperties(),
43
+ billingAddress: cart.billingAddress,
44
+ cart: cartReference,
45
+ country: cart.country,
46
+ custom: cart.custom,
47
+ customer: {
48
+ typeId: "customer",
49
+ id: cart.customerId,
50
+ },
51
+ customerGroup: cart.customerGroup,
52
+ customLineItems: [],
53
+ directDiscounts: cart.directDiscounts,
54
+ lineItems: cart.lineItems,
55
+ paymentInfo: cart.paymentInfo,
56
+ quoteRequestState: "Submitted",
57
+ shippingAddress: cart.shippingAddress,
58
+ taxCalculationMode: cart.taxCalculationMode,
59
+ taxedPrice: cart.taxedPrice,
60
+ taxMode: cart.taxMode,
61
+ taxRoundingMode: cart.taxRoundingMode,
62
+ totalPrice: cart.totalPrice,
63
+ store: cart.store,
64
+ };
65
+ return this.saveNew(context, resource);
66
+ }
67
+ }
@@ -0,0 +1,84 @@
1
+ import type {
2
+ InvalidJsonInputError,
3
+ StagedQuote,
4
+ StagedQuoteSetCustomFieldAction,
5
+ StagedQuoteSetCustomTypeAction,
6
+ StagedQuoteTransitionStateAction,
7
+ StagedQuoteUpdateAction,
8
+ StateReference,
9
+ } from "@commercetools/platform-sdk";
10
+ import { CommercetoolsError } from "~src/exceptions";
11
+ import type { Writable } from "~src/types";
12
+ import type { RepositoryContext, UpdateHandlerInterface } from "../abstract";
13
+ import { AbstractUpdateHandler } from "../abstract";
14
+ import { getReferenceFromResourceIdentifier } from "../helpers";
15
+
16
+ export class StagedQuoteUpdateHandler
17
+ extends AbstractUpdateHandler
18
+ implements
19
+ Partial<UpdateHandlerInterface<StagedQuote, StagedQuoteUpdateAction>>
20
+ {
21
+ setCustomField(
22
+ context: RepositoryContext,
23
+ resource: StagedQuote,
24
+ { name, value }: StagedQuoteSetCustomFieldAction,
25
+ ) {
26
+ if (!resource.custom) {
27
+ throw new Error("Resource has no custom field");
28
+ }
29
+ resource.custom.fields[name] = value;
30
+ }
31
+
32
+ setCustomType(
33
+ context: RepositoryContext,
34
+ resource: Writable<StagedQuote>,
35
+ { type, fields }: StagedQuoteSetCustomTypeAction,
36
+ ) {
37
+ if (!type) {
38
+ resource.custom = undefined;
39
+ } else {
40
+ const resolvedType = this._storage.getByResourceIdentifier(
41
+ context.projectKey,
42
+ type,
43
+ );
44
+ if (!resolvedType) {
45
+ throw new Error(`Type ${type} not found`);
46
+ }
47
+
48
+ resource.custom = {
49
+ type: {
50
+ typeId: "type",
51
+ id: resolvedType.id,
52
+ },
53
+ fields: fields || {},
54
+ };
55
+ }
56
+ }
57
+
58
+ transitionState(
59
+ context: RepositoryContext,
60
+ resource: Writable<StagedQuote>,
61
+ { state, force }: StagedQuoteTransitionStateAction,
62
+ ) {
63
+ let stateReference: StateReference | undefined = undefined;
64
+ if (state) {
65
+ stateReference = getReferenceFromResourceIdentifier<StateReference>(
66
+ state,
67
+ context.projectKey,
68
+ this._storage,
69
+ );
70
+ resource.state = stateReference;
71
+ } else {
72
+ throw new CommercetoolsError<InvalidJsonInputError>(
73
+ {
74
+ code: "InvalidJsonInput",
75
+ message: "Request body does not contain valid JSON.",
76
+ detailedErrorMessage: "actions -> state: Missing required value",
77
+ },
78
+ 400,
79
+ );
80
+ }
81
+
82
+ return resource;
83
+ }
84
+ }