@labdigital/commercetools-mock 0.5.20 → 0.5.23

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.
@@ -1,3 +1,4 @@
1
+ import { GetParams } from 'repositories/abstract';
1
2
  import { AbstractStorage } from './storage';
2
3
  import { RepositoryMap, ResourceMap, Services } from './types';
3
4
  export declare class ProjectAPI {
@@ -6,6 +7,6 @@ export declare class ProjectAPI {
6
7
  private _services;
7
8
  constructor(projectKey: string, services: Services, storage: AbstractStorage);
8
9
  add<ReferenceTypeId extends keyof ResourceMap>(typeId: ReferenceTypeId | 'custom-object', resource: ResourceMap[ReferenceTypeId]): void;
9
- get<ReferenceTypeId extends keyof ResourceMap>(typeId: ReferenceTypeId, id: string): ResourceMap[ReferenceTypeId];
10
+ get<ReferenceTypeId extends keyof ResourceMap>(typeId: ReferenceTypeId, id: string, params: GetParams): ResourceMap[ReferenceTypeId];
10
11
  getRepository<ReferenceTypeId extends keyof RepositoryMap>(typeId: ReferenceTypeId): RepositoryMap[ReferenceTypeId];
11
12
  }
@@ -1,4 +1,4 @@
1
- import { Cart, CartAddLineItemAction, CartDraft, CartRemoveLineItemAction, CartSetBillingAddressAction, CartSetCountryAction, CartSetCustomerEmailAction, CartSetCustomFieldAction, CartSetCustomTypeAction, CartSetLocaleAction, CartSetShippingAddressAction, ReferenceTypeId } from '@commercetools/platform-sdk';
1
+ import { Cart, CartAddLineItemAction, CartDraft, CartRemoveLineItemAction, CartSetBillingAddressAction, CartSetCountryAction, CartSetCustomerEmailAction, CartSetCustomFieldAction, CartSetCustomTypeAction, CartSetLocaleAction, CartSetShippingAddressAction, CartSetShippingMethodAction, LineItem, LineItemDraft, ReferenceTypeId } from '@commercetools/platform-sdk';
2
2
  import { AbstractResourceRepository } from './abstract';
3
3
  import { Writable } from '../types';
4
4
  export declare class CartRepository extends AbstractResourceRepository {
@@ -9,6 +9,7 @@ export declare class CartRepository extends AbstractResourceRepository {
9
9
  addLineItem: (projectKey: string, resource: Writable<Cart>, { productId, variantId, sku, quantity }: CartAddLineItemAction) => void;
10
10
  removeLineItem: (projectKey: string, resource: Writable<Cart>, { lineItemId, quantity }: CartRemoveLineItemAction) => void;
11
11
  setBillingAddress: (projectKey: string, resource: Writable<Cart>, { address }: CartSetBillingAddressAction) => void;
12
+ setShippingMethod: (projectKey: string, resource: Writable<Cart>, { shippingMethod }: CartSetShippingMethodAction) => void;
12
13
  setCountry: (projectKey: string, resource: Writable<Cart>, { country }: CartSetCountryAction) => void;
13
14
  setCustomerEmail: (projectKey: string, resource: Writable<Cart>, { email }: CartSetCustomerEmailAction) => void;
14
15
  setCustomField: (projectKey: string, resource: Cart, { name, value }: CartSetCustomFieldAction) => void;
@@ -16,4 +17,5 @@ export declare class CartRepository extends AbstractResourceRepository {
16
17
  setLocale: (projectKey: string, resource: Writable<Cart>, { locale }: CartSetLocaleAction) => void;
17
18
  setShippingAddress: (projectKey: string, resource: Writable<Cart>, { address }: CartSetShippingAddressAction) => void;
18
19
  };
20
+ draftLineItemtoLineItem: (projectKey: string, draftLineItem: LineItemDraft) => LineItem;
19
21
  }
@@ -1,4 +1,4 @@
1
- import { Order, OrderAddPaymentAction, OrderChangeOrderStateAction, OrderChangePaymentStateAction, OrderFromCartDraft, OrderImportDraft, OrderSetBillingAddressAction, OrderSetCustomerEmailAction, OrderSetCustomFieldAction, OrderSetCustomTypeAction, OrderSetLocaleAction, OrderSetOrderNumberAction, OrderSetShippingAddressAction, OrderSetStoreAction, ReferenceTypeId } from '@commercetools/platform-sdk';
1
+ import { Order, OrderAddPaymentAction, OrderChangeOrderStateAction, OrderChangePaymentStateAction, OrderFromCartDraft, OrderImportDraft, OrderSetBillingAddressAction, OrderSetCustomerEmailAction, OrderSetCustomFieldAction, OrderSetCustomTypeAction, OrderSetLocaleAction, OrderSetOrderNumberAction, OrderSetShippingAddressAction, OrderSetStoreAction, OrderTransitionStateAction, ReferenceTypeId } from '@commercetools/platform-sdk';
2
2
  import { AbstractResourceRepository, QueryParams } from './abstract';
3
3
  import { Writable } from '../types';
4
4
  export declare class OrderRepository extends AbstractResourceRepository {
@@ -12,6 +12,7 @@ export declare class OrderRepository extends AbstractResourceRepository {
12
12
  addPayment: (projectKey: string, resource: Writable<Order>, { payment }: OrderAddPaymentAction) => void;
13
13
  changeOrderState: (projectKey: string, resource: Writable<Order>, { orderState }: OrderChangeOrderStateAction) => void;
14
14
  changePaymentState: (projectKey: string, resource: Writable<Order>, { paymentState }: OrderChangePaymentStateAction) => void;
15
+ transitionState: (projectKey: string, resource: Writable<Order>, { state }: OrderTransitionStateAction) => void;
15
16
  setBillingAddress: (projectKey: string, resource: Writable<Order>, { address }: OrderSetBillingAddressAction) => void;
16
17
  setCustomerEmail: (projectKey: string, resource: Writable<Order>, { email }: OrderSetCustomerEmailAction) => void;
17
18
  setCustomField: (projectKey: string, resource: Order, { name, value }: OrderSetCustomFieldAction) => void;
@@ -2,8 +2,11 @@ import AbstractService from './abstract';
2
2
  import { Router } from 'express';
3
3
  import { CartRepository } from '../repositories/cart';
4
4
  import { AbstractStorage } from '../storage';
5
+ import { OrderRepository } from '../repositories/order';
5
6
  export declare class CartService extends AbstractService {
6
7
  repository: CartRepository;
8
+ orderRepository: OrderRepository;
7
9
  constructor(parent: Router, storage: AbstractStorage);
8
10
  getBasePath(): string;
11
+ extraRoutes(parent: Router): void;
9
12
  }
@@ -9,4 +9,5 @@ export declare class MyCustomerService extends AbstractService {
9
9
  registerRoutes(parent: Router): void;
10
10
  getMe(request: Request, response: Response): Response<any, Record<string, any>>;
11
11
  signUp(request: Request, response: Response): Response<any, Record<string, any>>;
12
+ signIn(request: Request, response: Response): Response<any, Record<string, any>>;
12
13
  }
@@ -0,0 +1,10 @@
1
+ import AbstractService from './abstract';
2
+ import { Router } from 'express';
3
+ import { AbstractStorage } from '../storage';
4
+ import { OrderRepository } from '../repositories/order';
5
+ export declare class MyOrderService extends AbstractService {
6
+ repository: OrderRepository;
7
+ constructor(parent: Router, storage: AbstractStorage);
8
+ getBasePath(): string;
9
+ registerRoutes(parent: Router): void;
10
+ }
package/dist/types.d.ts CHANGED
@@ -18,7 +18,7 @@ export declare type Writable<T> = {
18
18
  -readonly [P in keyof T]: Writable<T[P]>;
19
19
  };
20
20
  export declare type RepositoryTypes = ReferenceTypeId | 'product-projection';
21
- export declare type ServiceTypes = RepositoryTypes | 'my-cart' | 'my-payment' | 'my-customer';
21
+ export declare type ServiceTypes = RepositoryTypes | 'my-cart' | 'my-order' | 'my-payment' | 'my-customer';
22
22
  export declare type Services = Partial<{
23
23
  [index in ServiceTypes]: AbstractService;
24
24
  }>;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.5.20",
2
+ "version": "0.5.23",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
package/src/.env ADDED
File without changes
package/src/ctMock.ts CHANGED
@@ -38,6 +38,7 @@ import { TaxCategoryService } from './services/tax-category'
38
38
  import { TypeService } from './services/type'
39
39
  import { ZoneService } from './services/zone'
40
40
  import { MyCustomerService } from './services/my-customer'
41
+ import { MyOrderService } from './services/my-order'
41
42
 
42
43
  export type CommercetoolsMockOptions = {
43
44
  validateCredentials: boolean
@@ -164,6 +165,7 @@ export class CommercetoolsMock {
164
165
  order: new OrderService(projectRouter, this._storage),
165
166
  payment: new PaymentService(projectRouter, this._storage),
166
167
  'my-cart': new MyCartService(projectRouter, this._storage),
168
+ 'my-order': new MyOrderService(projectRouter, this._storage),
167
169
  'my-customer': new MyCustomerService(projectRouter, this._storage),
168
170
  'my-payment': new MyPaymentService(projectRouter, this._storage),
169
171
  'shipping-method': new ShippingMethodService(
package/src/projectAPI.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { GetParams } from 'repositories/abstract'
1
2
  import { getBaseResourceProperties } from './helpers'
2
3
  import { AbstractStorage } from './storage'
3
4
  import { RepositoryMap, ResourceMap, Services } from './types'
@@ -39,13 +40,14 @@ export class ProjectAPI {
39
40
 
40
41
  get<ReferenceTypeId extends keyof ResourceMap>(
41
42
  typeId: ReferenceTypeId,
42
- id: string
43
+ id: string,
44
+ params: GetParams
43
45
  ): ResourceMap[ReferenceTypeId] {
44
46
  return this._storage.get(
45
47
  this.projectKey,
46
48
  typeId,
47
49
  id,
48
- {}
50
+ params
49
51
  ) as ResourceMap[ReferenceTypeId]
50
52
  }
51
53
 
@@ -44,6 +44,7 @@ export abstract class AbstractRepository {
44
44
 
45
45
  actions.forEach(action => {
46
46
  const updateFunc = this.actions[action.action]
47
+
47
48
  if (!updateFunc) {
48
49
  console.error(`No mock implemented for update action ${action.action}`)
49
50
  return
@@ -10,8 +10,10 @@ import {
10
10
  CartSetCustomTypeAction,
11
11
  CartSetLocaleAction,
12
12
  CartSetShippingAddressAction,
13
+ CartSetShippingMethodAction,
13
14
  GeneralError,
14
15
  LineItem,
16
+ LineItemDraft,
15
17
  Product,
16
18
  ProductPagedQueryResponse,
17
19
  ProductVariant,
@@ -30,10 +32,14 @@ export class CartRepository extends AbstractResourceRepository {
30
32
  }
31
33
 
32
34
  create(projectKey: string, draft: CartDraft): Cart {
35
+ const lineItems = draft.lineItems?.map(draftLineItem =>
36
+ this.draftLineItemtoLineItem(projectKey, draftLineItem)
37
+ )
38
+
33
39
  const resource: Cart = {
34
40
  ...getBaseResourceProperties(),
35
41
  cartState: 'Active',
36
- lineItems: [],
42
+ lineItems: lineItems ?? [],
37
43
  customLineItems: [],
38
44
  totalPrice: {
39
45
  type: 'centPrecision',
@@ -48,6 +54,10 @@ export class CartRepository extends AbstractResourceRepository {
48
54
  origin: 'Customer',
49
55
  custom: createCustomFields(draft.custom, projectKey, this._storage),
50
56
  }
57
+
58
+ // @ts-ignore
59
+ resource.totalPrice.centAmount = calculateCartTotalPrice(resource)
60
+
51
61
  this.save(projectKey, resource)
52
62
  return resource
53
63
  }
@@ -204,6 +214,28 @@ export class CartRepository extends AbstractResourceRepository {
204
214
  ) => {
205
215
  resource.billingAddress = address
206
216
  },
217
+ setShippingMethod: (
218
+ projectKey: string,
219
+ resource: Writable<Cart>,
220
+ { shippingMethod }: CartSetShippingMethodAction
221
+ ) => {
222
+ const resolvedType = this._storage.getByResourceIdentifier(
223
+ projectKey,
224
+ //@ts-ignore
225
+ shippingMethod
226
+ )
227
+
228
+ if (!resolvedType) {
229
+ throw new Error(`Type ${shippingMethod} not found`)
230
+ }
231
+ //@ts-ignore
232
+ resource.shippingInfo = {
233
+ shippingMethod: {
234
+ typeId: 'shipping-method',
235
+ id: resolvedType.id,
236
+ },
237
+ }
238
+ },
207
239
  setCountry: (
208
240
  projectKey: string,
209
241
  resource: Writable<Cart>,
@@ -268,6 +300,91 @@ export class CartRepository extends AbstractResourceRepository {
268
300
  resource.shippingAddress = address
269
301
  },
270
302
  }
303
+ draftLineItemtoLineItem = (
304
+ projectKey: string,
305
+ draftLineItem: LineItemDraft
306
+ ): LineItem => {
307
+ const { productId, quantity } = draftLineItem
308
+ // @ts-ignore
309
+ let variantId = draftLineItem.variant.id
310
+ // @ts-ignore
311
+ let sku = draftLineItem.variant.sku
312
+ let product: Product | null = null
313
+ let variant: ProductVariant | undefined
314
+
315
+ if (productId && variantId) {
316
+ // Fetch product and variant by ID
317
+ product = this._storage.get(projectKey, 'product', productId, {})
318
+ } else if (sku) {
319
+ // Fetch product and variant by SKU
320
+ const items = this._storage.query(projectKey, 'product', {
321
+ where: [
322
+ `masterData(current(masterVariant(sku="${sku}"))) or masterData(current(variants(sku="${sku}")))`,
323
+ ],
324
+ }) as ProductPagedQueryResponse
325
+
326
+ if (items.count === 1) {
327
+ product = items.results[0]
328
+ }
329
+ }
330
+
331
+ if (!product) {
332
+ // Check if product is found
333
+ throw new CommercetoolsError<GeneralError>({
334
+ code: 'General',
335
+ message: sku
336
+ ? `A product containing a variant with SKU '${sku}' not found.`
337
+ : `A product with ID '${productId}' not found.`,
338
+ })
339
+ }
340
+
341
+ // Find matching variant
342
+ variant = [
343
+ product.masterData.current.masterVariant,
344
+ ...product.masterData.current.variants,
345
+ ].find(x => {
346
+ if (sku) return x.sku === sku
347
+ if (variantId) return x.id === variantId
348
+ return false
349
+ })
350
+
351
+ if (!variant) {
352
+ // Check if variant is found
353
+ throw new Error(
354
+ sku
355
+ ? `A variant with SKU '${sku}' for product '${product.id}' not found.`
356
+ : `A variant with ID '${variantId}' for product '${product.id}' not found.`
357
+ )
358
+ }
359
+
360
+ const price = variant.prices?.[0]
361
+
362
+ const quant = quantity ?? 1
363
+
364
+ if (!price) {
365
+ throw new Error(`Price not set on ${productId}`)
366
+ }
367
+
368
+ return {
369
+ id: uuidv4(),
370
+ productId: product.id,
371
+ productKey: product.key,
372
+ name: product.masterData.current.name,
373
+ productSlug: product.masterData.current.slug,
374
+ productType: product.productType,
375
+ variant,
376
+ price: price,
377
+ totalPrice: {
378
+ ...price.value,
379
+ centAmount: price.value.centAmount * quant,
380
+ },
381
+ quantity: quant,
382
+ discountedPricePerQuantity: [],
383
+ lineItemMode: 'Standard',
384
+ priceMode: 'Platform',
385
+ state: [],
386
+ }
387
+ }
271
388
  }
272
389
 
273
390
  const calculateLineItemTotalPrice = (lineItem: LineItem): number =>
@@ -12,6 +12,7 @@ export class CustomerRepository extends AbstractResourceRepository {
12
12
  getTypeId(): ReferenceTypeId {
13
13
  return 'customer'
14
14
  }
15
+
15
16
  create(projectKey: string, draft: CustomerDraft): Customer {
16
17
  const resource: Customer = {
17
18
  ...getBaseResourceProperties(),
@@ -23,6 +24,7 @@ export class CustomerRepository extends AbstractResourceRepository {
23
24
  this.save(projectKey, resource)
24
25
  return resource
25
26
  }
27
+
26
28
  getMe(projectKey: string): Customer | undefined {
27
29
  const results = this._storage.query(projectKey, this.getTypeId(), {}) // grab the first customer you can find
28
30
  if (results.count > 0) {
@@ -24,7 +24,6 @@ export const createCustomFields = (
24
24
  if (!draft.type) return undefined
25
25
  if (!draft.type.typeId) return undefined
26
26
  if (!draft.fields) return undefined
27
-
28
27
  const typeResource = storage.getByResourceIdentifier(
29
28
  projectKey,
30
29
  draft.type
@@ -20,10 +20,14 @@ import {
20
20
  OrderSetOrderNumberAction,
21
21
  OrderSetShippingAddressAction,
22
22
  OrderSetStoreAction,
23
+ OrderState,
24
+ OrderStateTransitionMessage,
25
+ OrderTransitionStateAction,
23
26
  Product,
24
27
  ProductPagedQueryResponse,
25
28
  ProductVariant,
26
29
  ReferenceTypeId,
30
+ State,
27
31
  Store,
28
32
  } from '@commercetools/platform-sdk'
29
33
  import { AbstractResourceRepository, QueryParams } from './abstract'
@@ -252,6 +256,24 @@ export class OrderRepository extends AbstractResourceRepository {
252
256
  ) => {
253
257
  resource.paymentState = paymentState
254
258
  },
259
+ transitionState: (
260
+ projectKey: string,
261
+ resource: Writable<Order>,
262
+ { state }: OrderTransitionStateAction
263
+ ) => {
264
+ const resolvedType = this._storage.getByResourceIdentifier(
265
+ projectKey,
266
+ state
267
+ ) as State | null
268
+
269
+ if (!resolvedType) {
270
+ throw new Error(
271
+ `No state found with key=${state.key} or id=${state.key}`
272
+ )
273
+ }
274
+
275
+ resource.state = { typeId: 'state', id: resolvedType.id }
276
+ },
255
277
  setBillingAddress: (
256
278
  projectKey: string,
257
279
  resource: Writable<Order>,
@@ -2,16 +2,48 @@ import AbstractService from './abstract'
2
2
  import { Router } from 'express'
3
3
  import { CartRepository } from '../repositories/cart'
4
4
  import { AbstractStorage } from '../storage'
5
+ import { Cart, Order } from '@commercetools/platform-sdk'
6
+ import { OrderRepository } from '../repositories/order'
5
7
 
6
8
  export class CartService extends AbstractService {
7
9
  public repository: CartRepository
10
+ public orderRepository: OrderRepository
8
11
 
9
12
  constructor(parent: Router, storage: AbstractStorage) {
10
13
  super(parent)
11
14
  this.repository = new CartRepository(storage)
15
+ this.orderRepository = new OrderRepository(storage)
12
16
  }
13
17
 
14
18
  getBasePath() {
15
19
  return 'carts'
16
20
  }
21
+
22
+ extraRoutes(parent: Router) {
23
+ parent.post('/replicate', (request, response) => {
24
+ // @ts-ignore
25
+ const cartOrOrder: Cart | Order | null =
26
+ request.body.reference.typeId === 'order'
27
+ ? this.orderRepository.get(
28
+ request.params.projectKey,
29
+ request.body.reference.id
30
+ )
31
+ : this.repository.get(
32
+ request.params.projectKey,
33
+ request.body.reference.id
34
+ )
35
+
36
+ if (!cartOrOrder) {
37
+ return response.status(400).send()
38
+ }
39
+
40
+ const newCart = this.repository.create(request.params.projectKey, {
41
+ ...cartOrOrder,
42
+ currency: cartOrOrder.totalPrice.currencyCode,
43
+ discountCodes: [],
44
+ })
45
+
46
+ return response.status(200).send(newCart)
47
+ })
48
+ }
17
49
  }
@@ -26,6 +26,8 @@ export class MyCustomerService extends AbstractService {
26
26
 
27
27
  router.post('/signup', this.signUp.bind(this))
28
28
 
29
+ router.post('/login', this.signIn.bind(this))
30
+
29
31
  parent.use(`/${basePath}`, router)
30
32
  }
31
33
 
@@ -43,4 +45,27 @@ export class MyCustomerService extends AbstractService {
43
45
  const result = this._expandWithId(request, resource.id)
44
46
  return response.status(this.createStatusCode).send({ customer: result })
45
47
  }
48
+
49
+ signIn(request: Request, response: Response) {
50
+ const { email, password } = request.body
51
+ const encodedPassword = Buffer.from(password).toString('base64')
52
+
53
+ const result = this.repository.query(request.params.projectKey, {
54
+ where: [`email = "${email}"`, `password = "${encodedPassword}"`],
55
+ })
56
+
57
+ if (result.count === 0) {
58
+ return response.status(400).send({
59
+ message: 'Account with the given credentials not found.',
60
+ errors: [
61
+ {
62
+ code: 'InvalidCredentials',
63
+ message: 'Account with the given credentials not found.',
64
+ },
65
+ ],
66
+ })
67
+ }
68
+
69
+ return response.status(200).send({ customer: result.results[0] })
70
+ }
46
71
  }
@@ -0,0 +1,35 @@
1
+ import AbstractService from './abstract'
2
+ import { Router } from 'express'
3
+ import { AbstractStorage } from '../storage'
4
+ import { OrderRepository } from '../repositories/order'
5
+
6
+ export class MyOrderService extends AbstractService {
7
+ public repository: OrderRepository
8
+
9
+ constructor(parent: Router, storage: AbstractStorage) {
10
+ super(parent)
11
+ this.repository = new OrderRepository(storage)
12
+ }
13
+
14
+ getBasePath() {
15
+ return 'me'
16
+ }
17
+
18
+ registerRoutes(parent: Router) {
19
+ // Overwrite this function to be able to handle /me/active-cart path.
20
+ const basePath = this.getBasePath()
21
+ const router = Router({ mergeParams: true })
22
+
23
+ this.extraRoutes(router)
24
+
25
+ router.get('/orders/', this.get.bind(this))
26
+ router.get('/orders/:id', this.getWithId.bind(this))
27
+
28
+ router.delete('/orders/:id', this.deletewithId.bind(this))
29
+
30
+ router.post('/orders/', this.post.bind(this))
31
+ router.post('/orders/:id', this.postWithId.bind(this))
32
+
33
+ parent.use(`/${basePath}`, router)
34
+ }
35
+ }
package/src/types.ts CHANGED
@@ -21,6 +21,7 @@ export type RepositoryTypes = ReferenceTypeId | 'product-projection'
21
21
  export type ServiceTypes =
22
22
  | RepositoryTypes
23
23
  | 'my-cart'
24
+ | 'my-order'
24
25
  | 'my-payment'
25
26
  | 'my-customer'
26
27