,
19 | action: T,
20 | ) => void;
21 |
22 | type TaxCategoryUpdateActions = {
23 | [P in TaxCategoryUpdateAction as P["action"]]: TaxCategoryUpdateHandlerMethod;
24 | };
25 |
26 | export class TaxCategoryUpdateHandler
27 | extends AbstractUpdateHandler
28 | implements TaxCategoryUpdateActions
29 | {
30 | addTaxRate(
31 | context: RepositoryContext,
32 | resource: Writable,
33 | { taxRate }: TaxCategoryAddTaxRateAction,
34 | ) {
35 | if (resource.rates === undefined) {
36 | resource.rates = [];
37 | }
38 | resource.rates.push(taxRateFromTaxRateDraft(taxRate));
39 | }
40 |
41 | changeName(
42 | context: RepositoryContext,
43 | resource: Writable,
44 | { name }: TaxCategoryChangeNameAction,
45 | ) {
46 | resource.name = name;
47 | }
48 |
49 | removeTaxRate(
50 | context: RepositoryContext,
51 | resource: Writable,
52 | { taxRateId }: TaxCategoryRemoveTaxRateAction,
53 | ) {
54 | if (resource.rates === undefined) {
55 | resource.rates = [];
56 | }
57 | resource.rates = resource.rates.filter(
58 | (taxRate) => taxRate.id !== taxRateId,
59 | );
60 | }
61 |
62 | replaceTaxRate(
63 | context: RepositoryContext,
64 | resource: Writable,
65 | { taxRateId, taxRate }: TaxCategoryReplaceTaxRateAction,
66 | ) {
67 | if (resource.rates === undefined) {
68 | resource.rates = [];
69 | }
70 |
71 | const taxRateObj = taxRateFromTaxRateDraft(taxRate);
72 | for (let i = 0; i < resource.rates.length; i++) {
73 | const rate = resource.rates[i];
74 | if (rate.id === taxRateId) {
75 | resource.rates[i] = taxRateObj;
76 | }
77 | }
78 | }
79 |
80 | setDescription(
81 | context: RepositoryContext,
82 | resource: Writable,
83 | { description }: TaxCategorySetDescriptionAction,
84 | ) {
85 | resource.description = description;
86 | }
87 |
88 | setKey(
89 | context: RepositoryContext,
90 | resource: Writable,
91 | { key }: TaxCategorySetKeyAction,
92 | ) {
93 | resource.key = key;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/repositories/tax-category/helpers.ts:
--------------------------------------------------------------------------------
1 | import type { TaxRate, TaxRateDraft } from "@commercetools/platform-sdk";
2 | import { v4 as uuidv4 } from "uuid";
3 |
4 | export const taxRateFromTaxRateDraft = (draft: TaxRateDraft): TaxRate => ({
5 | ...draft,
6 | id: uuidv4(),
7 | amount: draft.amount || 0,
8 | });
9 |
--------------------------------------------------------------------------------
/src/repositories/tax-category/index.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | TaxCategory,
3 | TaxCategoryDraft,
4 | } from "@commercetools/platform-sdk";
5 | import type { Config } from "~src/config";
6 | import { getBaseResourceProperties } from "~src/helpers";
7 | import type { RepositoryContext } from "../abstract";
8 | import { AbstractResourceRepository } from "../abstract";
9 | import { TaxCategoryUpdateHandler } from "./actions";
10 | import { taxRateFromTaxRateDraft } from "./helpers";
11 |
12 | export class TaxCategoryRepository extends AbstractResourceRepository<"tax-category"> {
13 | constructor(config: Config) {
14 | super("tax-category", config);
15 | this.actions = new TaxCategoryUpdateHandler(this._storage);
16 | }
17 |
18 | create(context: RepositoryContext, draft: TaxCategoryDraft): TaxCategory {
19 | const resource: TaxCategory = {
20 | ...getBaseResourceProperties(),
21 | ...draft,
22 | rates: draft.rates?.map(taxRateFromTaxRateDraft) || [],
23 | };
24 | return this.saveNew(context, resource);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/repositories/type/index.ts:
--------------------------------------------------------------------------------
1 | import type { Type, TypeDraft } 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 { TypeUpdateHandler } from "./actions";
7 |
8 | export class TypeRepository extends AbstractResourceRepository<"type"> {
9 | constructor(config: Config) {
10 | super("type", config);
11 | this.actions = new TypeUpdateHandler(config.storage);
12 | }
13 |
14 | create(context: RepositoryContext, draft: TypeDraft): Type {
15 | const resource: Type = {
16 | ...getBaseResourceProperties(),
17 | key: draft.key,
18 | name: draft.name,
19 | resourceTypeIds: draft.resourceTypeIds,
20 | fieldDefinitions: draft.fieldDefinitions || [],
21 | description: draft.description,
22 | };
23 | return this.saveNew(context, resource);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/repositories/zone.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | Zone,
3 | ZoneAddLocationAction,
4 | ZoneChangeNameAction,
5 | ZoneDraft,
6 | ZoneRemoveLocationAction,
7 | ZoneSetDescriptionAction,
8 | ZoneSetKeyAction,
9 | ZoneUpdateAction,
10 | } from "@commercetools/platform-sdk";
11 | import type { Config } from "~src/config";
12 | import { getBaseResourceProperties } from "../helpers";
13 | import type { Writable } from "../types";
14 | import type { RepositoryContext, UpdateHandlerInterface } from "./abstract";
15 | import { AbstractResourceRepository, AbstractUpdateHandler } from "./abstract";
16 |
17 | export class ZoneRepository extends AbstractResourceRepository<"zone"> {
18 | constructor(config: Config) {
19 | super("zone", config);
20 | this.actions = new ZoneUpdateHandler(config.storage);
21 | }
22 |
23 | create(context: RepositoryContext, draft: ZoneDraft): Zone {
24 | const resource: Zone = {
25 | ...getBaseResourceProperties(),
26 | key: draft.key,
27 | locations: draft.locations || [],
28 | name: draft.name,
29 | description: draft.description,
30 | };
31 | return this.saveNew(context, resource);
32 | }
33 | }
34 |
35 | class ZoneUpdateHandler
36 | extends AbstractUpdateHandler
37 | implements Partial>
38 | {
39 | addLocation(
40 | context: RepositoryContext,
41 | resource: Writable,
42 | { location }: ZoneAddLocationAction,
43 | ) {
44 | resource.locations.push(location);
45 | }
46 |
47 | changeName(
48 | context: RepositoryContext,
49 | resource: Writable,
50 | { name }: ZoneChangeNameAction,
51 | ) {
52 | resource.name = name;
53 | }
54 |
55 | removeLocation(
56 | context: RepositoryContext,
57 | resource: Writable,
58 | { location }: ZoneRemoveLocationAction,
59 | ) {
60 | resource.locations = resource.locations.filter(
61 | (loc) =>
62 | !(loc.country === location.country && loc.state === location.state),
63 | );
64 | }
65 |
66 | setDescription(
67 | context: RepositoryContext,
68 | resource: Writable,
69 | { description }: ZoneSetDescriptionAction,
70 | ) {
71 | resource.description = description;
72 | }
73 |
74 | setKey(
75 | context: RepositoryContext,
76 | resource: Writable,
77 | { key }: ZoneSetKeyAction,
78 | ) {
79 | resource.key = key;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/schemas/update-request.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | const UpdateActionSchema = z
4 | .object({
5 | action: z.string(),
6 | })
7 | .passthrough();
8 |
9 | export const updateRequestSchema = z.object({
10 | version: z.number(),
11 | actions: z.array(UpdateActionSchema),
12 | });
13 |
--------------------------------------------------------------------------------
/src/server.ts:
--------------------------------------------------------------------------------
1 | import { CommercetoolsMock } from "./index";
2 |
3 | process.on("SIGINT", () => {
4 | console.info("Stopping server...");
5 | process.exit();
6 | });
7 |
8 | const instance = new CommercetoolsMock();
9 |
10 | let port = 3000;
11 |
12 | if (process.env.HTTP_SERVER_PORT)
13 | port = Number.parseInt(process.env.HTTP_SERVER_PORT);
14 |
15 | instance.runServer(port);
16 |
--------------------------------------------------------------------------------
/src/services/as-associate-cart.ts:
--------------------------------------------------------------------------------
1 | import { Router } from "express";
2 | import type { CartRepository } from "../repositories/cart";
3 | import AbstractService from "./abstract";
4 |
5 | export class AsAssociateCartService extends AbstractService {
6 | public repository: CartRepository;
7 |
8 | constructor(parent: Router, repository: CartRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "carts";
15 | }
16 |
17 | registerRoutes(parent: Router) {
18 | const basePath = this.getBasePath();
19 | const router = Router({ mergeParams: true });
20 |
21 | this.extraRoutes(router);
22 |
23 | router.get("/", this.get.bind(this));
24 | router.get("/:id", this.getWithId.bind(this));
25 |
26 | router.delete("/:id", this.deleteWithId.bind(this));
27 |
28 | router.post("/", this.post.bind(this));
29 | router.post("/:id", this.postWithId.bind(this));
30 |
31 | parent.use(`/${basePath}`, router);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/services/as-associate-order.test.ts:
--------------------------------------------------------------------------------
1 | import assert from "node:assert";
2 | import type { Order } from "@commercetools/platform-sdk";
3 | import supertest from "supertest";
4 | import { afterEach, beforeEach, describe, expect, test } from "vitest";
5 | import { CommercetoolsMock } from "../index";
6 |
7 | describe("Order Query", () => {
8 | const ctMock = new CommercetoolsMock();
9 | let order: Order | undefined;
10 | const projectKey = "dummy";
11 | const customerId = "5fac8fca-2484-4b14-a1d1-cfdce2f8d3c4";
12 | const businessUnitKey = "business-unit";
13 |
14 | beforeEach(async () => {
15 | let response = await supertest(ctMock.app)
16 | .post(
17 | `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/carts`,
18 | )
19 | .send({
20 | currency: "EUR",
21 | custom: {
22 | type: {
23 | key: "my-cart",
24 | },
25 | fields: {
26 | description: "example description",
27 | },
28 | },
29 | });
30 | expect(response.status).toBe(201);
31 | const cart = response.body;
32 |
33 | response = await supertest(ctMock.app)
34 | .post(
35 | `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/orders`,
36 | )
37 | .send({
38 | cart: {
39 | typeId: "cart",
40 | id: cart.id,
41 | },
42 | orderNumber: "foobar",
43 | });
44 | expect(response.status).toBe(201);
45 | order = response.body;
46 | });
47 |
48 | afterEach(() => {
49 | ctMock.clear();
50 | });
51 |
52 | test("no filter", async () => {
53 | assert(order, "order not created");
54 |
55 | const response = await supertest(ctMock.app).get(
56 | `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/orders`,
57 | );
58 | expect(response.status).toBe(200);
59 | expect(response.body.count).toBe(1);
60 | expect(response.body.total).toBe(1);
61 | expect(response.body.offset).toBe(0);
62 | expect(response.body.limit).toBe(20);
63 | });
64 | });
65 |
--------------------------------------------------------------------------------
/src/services/as-associate-order.ts:
--------------------------------------------------------------------------------
1 | import { Router } from "express";
2 | import type { MyOrderRepository } from "../repositories/my-order";
3 | import AbstractService from "./abstract";
4 |
5 | export class AsAssociateOrderService extends AbstractService {
6 | public repository: MyOrderRepository;
7 |
8 | constructor(parent: Router, repository: MyOrderRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "orders";
15 | }
16 |
17 | registerRoutes(parent: Router) {
18 | const basePath = this.getBasePath();
19 | const router = Router({ mergeParams: true });
20 |
21 | this.extraRoutes(router);
22 |
23 | router.get("/", this.get.bind(this));
24 | router.get("/:id", this.getWithId.bind(this));
25 |
26 | router.delete("/:id", this.deleteWithId.bind(this));
27 |
28 | router.post("/", this.post.bind(this));
29 | router.post("/:id", this.postWithId.bind(this));
30 |
31 | parent.use(`/${basePath}`, router);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/services/as-associate-quote-request.ts:
--------------------------------------------------------------------------------
1 | import { Router } from "express";
2 | import type { MyQuoteRequestRepository } from "~src/repositories/my-quote-request";
3 | import type { MyOrderRepository } from "../repositories/my-order";
4 | import AbstractService from "./abstract";
5 |
6 | export class AsAssociateQuoteRequestService extends AbstractService {
7 | public repository: MyQuoteRequestRepository;
8 |
9 | constructor(parent: Router, repository: MyQuoteRequestRepository) {
10 | super(parent);
11 | this.repository = repository;
12 | }
13 |
14 | getBasePath() {
15 | return "quote-requests";
16 | }
17 |
18 | registerRoutes(parent: Router) {
19 | const basePath = this.getBasePath();
20 | const router = Router({ mergeParams: true });
21 |
22 | this.extraRoutes(router);
23 |
24 | router.get("/", this.get.bind(this));
25 | router.get("/:id", this.getWithId.bind(this));
26 |
27 | router.delete("/:id", this.deleteWithId.bind(this));
28 |
29 | router.post("/", this.post.bind(this));
30 | router.post("/:id", this.postWithId.bind(this));
31 |
32 | parent.use(`/${basePath}`, router);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/services/as-associate.ts:
--------------------------------------------------------------------------------
1 | import { Router } from "express";
2 | import type {
3 | AsAssociateCartRepository,
4 | AsAssociateOrderRepository,
5 | AsAssociateQuoteRequestRepository,
6 | } from "~src/repositories/as-associate";
7 | import { AsAssociateCartService } from "./as-associate-cart";
8 | import { AsAssociateOrderService } from "./as-associate-order";
9 | import { AsAssociateQuoteRequestService } from "./as-associate-quote-request";
10 |
11 | type Repositories = {
12 | cart: AsAssociateCartRepository;
13 | order: AsAssociateOrderRepository;
14 | "quote-request": AsAssociateQuoteRequestRepository;
15 | };
16 |
17 | export class AsAssociateService {
18 | router: Router;
19 |
20 | subServices: {
21 | cart: AsAssociateCartService;
22 | order: AsAssociateOrderService;
23 | "quote-request": AsAssociateQuoteRequestService;
24 | };
25 |
26 | constructor(parent: Router, repositories: Repositories) {
27 | this.router = Router({ mergeParams: true });
28 |
29 | this.subServices = {
30 | order: new AsAssociateOrderService(this.router, repositories.order),
31 | cart: new AsAssociateCartService(this.router, repositories.cart),
32 | "quote-request": new AsAssociateQuoteRequestService(
33 | this.router,
34 | repositories["quote-request"],
35 | ),
36 | };
37 | parent.use(
38 | "/as-associate/:associateId/in-business-unit/key=:businessUnitId",
39 | this.router,
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/services/associate-roles.test.ts:
--------------------------------------------------------------------------------
1 | import type { AssociateRole } from "@commercetools/platform-sdk";
2 | import supertest from "supertest";
3 | import { afterEach, beforeEach, describe, expect, test } from "vitest";
4 | import { CommercetoolsMock } from "../ctMock";
5 |
6 | describe("Associate roles query", () => {
7 | const ctMock = new CommercetoolsMock();
8 | let associateRole: AssociateRole | undefined;
9 |
10 | beforeEach(async () => {
11 | const response = await supertest(ctMock.app)
12 | .post("/dummy/associate-roles")
13 | .send({
14 | name: "example-role",
15 | buyerAssignable: false,
16 | key: "example-role-associate-role",
17 | permissions: ["ViewMyQuotes", "ViewMyOrders", "ViewMyCarts"],
18 | });
19 |
20 | expect(response.status).toBe(201);
21 |
22 | associateRole = response.body as AssociateRole;
23 | });
24 |
25 | afterEach(() => {
26 | ctMock.clear();
27 | });
28 |
29 | test("no filter", async () => {
30 | const response = await supertest(ctMock.app)
31 | .get("/dummy/associate-roles")
32 | .query("{}")
33 | .send();
34 |
35 | expect(response.status).toBe(200);
36 | expect(response.body.count).toBe(1);
37 |
38 | associateRole = response.body.results[0] as AssociateRole;
39 |
40 | expect(associateRole.key).toBe("example-role-associate-role");
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/src/services/associate-roles.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { AssociateRoleRepository } from "../repositories/associate-role";
3 | import AbstractService from "./abstract";
4 |
5 | export class AssociateRoleServices extends AbstractService {
6 | public repository: AssociateRoleRepository;
7 |
8 | constructor(parent: Router, repository: AssociateRoleRepository) {
9 | super(parent);
10 |
11 | this.repository = repository;
12 | }
13 |
14 | protected getBasePath(): string {
15 | return "associate-roles";
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/services/attribute-group.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { AttributeGroupRepository } from "../repositories/attribute-group";
3 | import AbstractService from "./abstract";
4 |
5 | export class AttributeGroupService extends AbstractService {
6 | public repository: AttributeGroupRepository;
7 |
8 | constructor(parent: Router, repository: AttributeGroupRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "attribute-groups";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/business-units.test.ts:
--------------------------------------------------------------------------------
1 | import type { BusinessUnit } from "@commercetools/platform-sdk";
2 | import supertest from "supertest";
3 | import { afterEach, beforeEach, describe, expect, test } from "vitest";
4 | import { CommercetoolsMock } from "../ctMock";
5 |
6 | describe("Business units query", () => {
7 | const ctMock = new CommercetoolsMock();
8 | let businessUnit: BusinessUnit | undefined;
9 |
10 | beforeEach(async () => {
11 | const response = await supertest(ctMock.app)
12 | .post("/dummy/business-units")
13 | .send({
14 | key: "example-business-unit",
15 | status: "Active",
16 | name: "Example Business Unit",
17 | unitType: "Company",
18 | });
19 |
20 | expect(response.status).toBe(201);
21 |
22 | businessUnit = response.body as BusinessUnit;
23 | });
24 |
25 | afterEach(() => {
26 | ctMock.clear();
27 | });
28 |
29 | test("no filter", async () => {
30 | const response = await supertest(ctMock.app)
31 | .get("/dummy/business-units")
32 | .query("{}")
33 | .send();
34 |
35 | expect(response.status).toBe(200);
36 | expect(response.body.count).toBe(1);
37 |
38 | businessUnit = response.body.results[0] as BusinessUnit;
39 |
40 | expect(businessUnit.key).toBe("example-business-unit");
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/src/services/business-units.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { BusinessUnitRepository } from "../repositories/business-unit";
3 | import AbstractService from "./abstract";
4 |
5 | export class BusinessUnitServices extends AbstractService {
6 | public repository: BusinessUnitRepository;
7 |
8 | constructor(parent: Router, repository: BusinessUnitRepository) {
9 | super(parent);
10 |
11 | this.repository = repository;
12 | }
13 |
14 | protected getBasePath(): string {
15 | return "business-units";
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/services/cart-discount.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { CartDiscountRepository } from "../repositories/cart-discount";
3 | import AbstractService from "./abstract";
4 |
5 | export class CartDiscountService extends AbstractService {
6 | public repository: CartDiscountRepository;
7 |
8 | constructor(parent: Router, repository: CartDiscountRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "cart-discounts";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/cart.ts:
--------------------------------------------------------------------------------
1 | import type { Cart, CartDraft, Order } from "@commercetools/platform-sdk";
2 | import type { Request, Response, Router } from "express";
3 | import type { CartRepository } from "../repositories/cart";
4 | import { getRepositoryContext } from "../repositories/helpers";
5 | import type { OrderRepository } from "../repositories/order";
6 | import AbstractService from "./abstract";
7 |
8 | export class CartService extends AbstractService {
9 | public repository: CartRepository;
10 |
11 | public orderRepository: OrderRepository;
12 |
13 | constructor(
14 | parent: Router,
15 | cartRepository: CartRepository,
16 | orderRepository: OrderRepository,
17 | ) {
18 | super(parent);
19 | this.repository = cartRepository;
20 | this.orderRepository = orderRepository;
21 | }
22 |
23 | getBasePath() {
24 | return "carts";
25 | }
26 |
27 | extraRoutes(parent: Router) {
28 | parent.post("/replicate", this.replicate.bind(this));
29 | }
30 |
31 | replicate(request: Request, response: Response) {
32 | const context = getRepositoryContext(request);
33 |
34 | // @ts-ignore
35 | const cartOrOrder: Cart | Order | null =
36 | request.body.reference.typeId === "order"
37 | ? this.orderRepository.get(context, request.body.reference.id)
38 | : this.repository.get(context, request.body.reference.id);
39 |
40 | if (!cartOrOrder) {
41 | response.status(400).send();
42 | return;
43 | }
44 |
45 | const cartDraft: CartDraft = {
46 | ...cartOrOrder,
47 | currency: cartOrOrder.totalPrice.currencyCode,
48 | discountCodes: [],
49 | shipping: [], // TODO: cartOrOrder.shipping,
50 | lineItems: cartOrOrder.lineItems.map((lineItem) => ({
51 | ...lineItem,
52 | variantId: lineItem.variant.id,
53 | sku: lineItem.variant.sku,
54 | })),
55 | };
56 |
57 | const newCart = this.repository.create(context, cartDraft);
58 |
59 | response.status(200).send(newCart);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/services/category.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { CategoryRepository } from "../repositories/category/index";
3 | import AbstractService from "./abstract";
4 |
5 | export class CategoryServices extends AbstractService {
6 | public repository: CategoryRepository;
7 |
8 | constructor(parent: Router, repository: CategoryRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "categories";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/channel.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { ChannelRepository } from "../repositories/channel";
3 | import AbstractService from "./abstract";
4 |
5 | export class ChannelService extends AbstractService {
6 | public repository: ChannelRepository;
7 |
8 | constructor(parent: Router, repository: ChannelRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "channels";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/custom-object.ts:
--------------------------------------------------------------------------------
1 | import type { CustomObjectDraft } from "@commercetools/platform-sdk";
2 | import type { Request, Response, Router } from "express";
3 | import type { CustomObjectRepository } from "../repositories/custom-object";
4 | import { getRepositoryContext } from "../repositories/helpers";
5 | import AbstractService from "./abstract";
6 |
7 | export class CustomObjectService extends AbstractService {
8 | public repository: CustomObjectRepository;
9 |
10 | constructor(parent: Router, repository: CustomObjectRepository) {
11 | super(parent);
12 | this.repository = repository;
13 | }
14 |
15 | getBasePath() {
16 | return "custom-objects";
17 | }
18 |
19 | extraRoutes(router: Router) {
20 | router.get("/:container", this.getWithContainer.bind(this));
21 | router.get("/:container/:key", this.getWithContainerAndKey.bind(this));
22 | router.post("/:container/:key", this.createWithContainerAndKey.bind(this));
23 | router.delete(
24 | "/:container/:key",
25 | this.deleteWithContainerAndKey.bind(this),
26 | );
27 | }
28 |
29 | getWithContainer(request: Request, response: Response) {
30 | const limit = this._parseParam(request.query.limit);
31 | const offset = this._parseParam(request.query.offset);
32 |
33 | const result = this.repository.queryWithContainer(
34 | getRepositoryContext(request),
35 | request.params.container,
36 | {
37 | expand: this._parseParam(request.query.expand),
38 | where: this._parseParam(request.query.where),
39 | limit: limit !== undefined ? Number(limit) : undefined,
40 | offset: offset !== undefined ? Number(offset) : undefined,
41 | },
42 | );
43 |
44 | response.status(200).send(result);
45 | }
46 |
47 | getWithContainerAndKey(request: Request, response: Response) {
48 | const result = this.repository.getWithContainerAndKey(
49 | getRepositoryContext(request),
50 | request.params.container,
51 | request.params.key,
52 | );
53 |
54 | if (!result) {
55 | response.status(404).send({ statusCode: 404 });
56 | return;
57 | }
58 | response.status(200).send(result);
59 | }
60 |
61 | createWithContainerAndKey(request: Request, response: Response) {
62 | const draft: CustomObjectDraft = {
63 | ...request.body,
64 | key: request.params.key,
65 | container: request.params.container,
66 | };
67 |
68 | const result = this.repository.create(getRepositoryContext(request), draft);
69 | response.status(200).send(result);
70 | }
71 |
72 | deleteWithContainerAndKey(request: Request, response: Response) {
73 | const current = this.repository.getWithContainerAndKey(
74 | getRepositoryContext(request),
75 | request.params.container,
76 | request.params.key,
77 | );
78 |
79 | if (!current) {
80 | response.status(404).send({ statusCode: 404 });
81 | return;
82 | }
83 |
84 | const result = this.repository.delete(
85 | getRepositoryContext(request),
86 | current.id,
87 | );
88 |
89 | response.status(200).send(result);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/services/customer-group.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { CustomerGroupRepository } from "../repositories/customer-group";
3 | import AbstractService from "./abstract";
4 |
5 | export class CustomerGroupService extends AbstractService {
6 | public repository: CustomerGroupRepository;
7 |
8 | constructor(parent: Router, repository: CustomerGroupRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "customer-groups";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/customer.ts:
--------------------------------------------------------------------------------
1 | import type { CustomerSignInResult } from "@commercetools/platform-sdk";
2 | import type { Router } from "express";
3 | import type { Request, Response } from "express";
4 | import type { CustomerRepository } from "../repositories/customer";
5 | import { getRepositoryContext } from "../repositories/helpers";
6 | import AbstractService from "./abstract";
7 |
8 | export class CustomerService extends AbstractService {
9 | public repository: CustomerRepository;
10 |
11 | constructor(parent: Router, repository: CustomerRepository) {
12 | super(parent);
13 | this.repository = repository;
14 | }
15 |
16 | getBasePath() {
17 | return "customers";
18 | }
19 |
20 | extraRoutes(parent: Router) {
21 | parent.post("/password-token", this.passwordResetToken.bind(this));
22 | parent.post("/password/reset", this.passwordReset.bind(this));
23 | parent.post("/email-token", this.confirmEmailToken.bind(this));
24 | }
25 |
26 | post(request: Request, response: Response) {
27 | const draft = request.body;
28 | const resource = this.repository.create(
29 | getRepositoryContext(request),
30 | draft,
31 | );
32 | const expanded = this._expandWithId(request, resource.id);
33 |
34 | const result: CustomerSignInResult = {
35 | customer: expanded,
36 | };
37 | response.status(this.createStatusCode).send(result);
38 | }
39 |
40 | passwordResetToken(request: Request, response: Response) {
41 | const customer = this.repository.passwordResetToken(
42 | getRepositoryContext(request),
43 | request.body,
44 | );
45 |
46 | response.status(200).send(customer);
47 | }
48 |
49 | passwordReset(request: Request, response: Response) {
50 | const customer = this.repository.passwordReset(
51 | getRepositoryContext(request),
52 | request.body,
53 | );
54 |
55 | response.status(200).send(customer);
56 | }
57 |
58 | confirmEmailToken(request: Request, response: Response) {
59 | const id = request.body.id;
60 | const token = this.repository.verifyEmailToken(
61 | getRepositoryContext(request),
62 | id,
63 | );
64 | response.status(200).send(token);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/services/discount-code.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { DiscountCodeRepository } from "../repositories/discount-code/index";
3 | import AbstractService from "./abstract";
4 |
5 | export class DiscountCodeService extends AbstractService {
6 | public repository: DiscountCodeRepository;
7 |
8 | constructor(parent: Router, repository: DiscountCodeRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "discount-codes";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/extension.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { ExtensionRepository } from "../repositories/extension";
3 | import AbstractService from "./abstract";
4 |
5 | export class ExtensionServices extends AbstractService {
6 | public repository: ExtensionRepository;
7 |
8 | constructor(parent: Router, repository: ExtensionRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "extensions";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/inventory-entry.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { InventoryEntryRepository } from "../repositories/inventory-entry";
3 | import AbstractService from "./abstract";
4 |
5 | export class InventoryEntryService extends AbstractService {
6 | public repository: InventoryEntryRepository;
7 |
8 | constructor(parent: Router, repository: InventoryEntryRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "inventory";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/my-business-unit.ts:
--------------------------------------------------------------------------------
1 | import { Router } from "express";
2 | import type { BusinessUnitRepository } from "~src/repositories/business-unit";
3 | import AbstractService from "./abstract";
4 |
5 | export class MyBusinessUnitService extends AbstractService {
6 | public repository: BusinessUnitRepository;
7 |
8 | constructor(parent: Router, repository: BusinessUnitRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "me";
15 | }
16 |
17 | registerRoutes(parent: Router) {
18 | // Overwrite this function to be able to handle /me/business-units path.
19 | const basePath = this.getBasePath();
20 | const router = Router({ mergeParams: true });
21 |
22 | this.extraRoutes(router);
23 |
24 | router.get("/business-units/", this.get.bind(this));
25 |
26 | parent.use(`/${basePath}`, router);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/services/my-cart.test.ts:
--------------------------------------------------------------------------------
1 | import type { Cart, MyCartDraft } from "@commercetools/platform-sdk";
2 | import supertest from "supertest";
3 | import { afterEach, beforeEach, describe, expect, test } from "vitest";
4 | import { CommercetoolsMock } from "../index";
5 |
6 | const ctMock = new CommercetoolsMock();
7 |
8 | describe("MyCart", () => {
9 | beforeEach(async () => {
10 | const response = await supertest(ctMock.app)
11 | .post("/dummy/types")
12 | .send({
13 | key: "custom-payment",
14 | name: {
15 | "nl-NL": "custom-payment",
16 | },
17 | resourceTypeIds: ["payment"],
18 | });
19 | expect(response.status).toBe(201);
20 | });
21 |
22 | afterEach(() => {
23 | ctMock.clear();
24 | });
25 |
26 | test("Create my cart", async () => {
27 | const draft: MyCartDraft = {
28 | currency: "EUR",
29 | };
30 |
31 | const response = await supertest(ctMock.app)
32 | .post("/dummy/me/carts")
33 | .send(draft);
34 |
35 | expect(response.status).toBe(201);
36 | expect(response.body).toEqual({
37 | id: expect.anything(),
38 | createdAt: expect.anything(),
39 | lastModifiedAt: expect.anything(),
40 | version: 1,
41 | cartState: "Active",
42 | discountCodes: [],
43 | directDiscounts: [],
44 | inventoryMode: "None",
45 | itemShippingAddresses: [],
46 | lineItems: [],
47 | customLineItems: [],
48 | shipping: [],
49 | shippingMode: "Single",
50 | totalPrice: {
51 | type: "centPrecision",
52 | centAmount: 0,
53 | currencyCode: "EUR",
54 | fractionDigits: 0,
55 | },
56 | taxMode: "Platform",
57 | taxRoundingMode: "HalfEven",
58 | taxCalculationMode: "LineItemLevel",
59 | refusedGifts: [],
60 | origin: "Customer",
61 | } as Cart);
62 | });
63 |
64 | test("Get my cart by ID", async () => {
65 | const draft: MyCartDraft = {
66 | currency: "EUR",
67 | };
68 | const createResponse = await supertest(ctMock.app)
69 | .post("/dummy/me/carts")
70 | .send(draft);
71 |
72 | const response = await supertest(ctMock.app).get(
73 | `/dummy/me/carts/${createResponse.body.id}`,
74 | );
75 |
76 | expect(response.status).toBe(200);
77 | expect(response.body).toEqual(createResponse.body);
78 | });
79 |
80 | test("Get my active cart", async () => {
81 | const draft: MyCartDraft = {
82 | currency: "EUR",
83 | };
84 | const createResponse = await supertest(ctMock.app)
85 | .post("/dummy/me/carts")
86 | .send(draft);
87 |
88 | const response = await supertest(ctMock.app).get("/dummy/me/active-cart");
89 |
90 | expect(response.status).toBe(200);
91 | expect(response.body).toEqual(createResponse.body);
92 | });
93 |
94 | test("Get my active cart which doesnt exists", async () => {
95 | const response = await supertest(ctMock.app).get("/dummy/me/active-cart");
96 |
97 | expect(response.status).toBe(404);
98 | });
99 | });
100 |
--------------------------------------------------------------------------------
/src/services/my-cart.ts:
--------------------------------------------------------------------------------
1 | import type { Request, Response } from "express";
2 | import { Router } from "express";
3 | import type { CartRepository } from "../repositories/cart";
4 | import AbstractService from "./abstract";
5 |
6 | export class MyCartService extends AbstractService {
7 | public repository: CartRepository;
8 |
9 | constructor(parent: Router, repository: CartRepository) {
10 | super(parent);
11 | this.repository = repository;
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("/active-cart", this.activeCart.bind(this));
26 | router.get("/carts/", this.get.bind(this));
27 | router.get("/carts/:id", this.getWithId.bind(this));
28 |
29 | router.delete("/carts/:id", this.deleteWithId.bind(this));
30 |
31 | router.post("/carts/", this.post.bind(this));
32 | router.post("/carts/:id", this.postWithId.bind(this));
33 |
34 | parent.use(`/${basePath}`, router);
35 | }
36 |
37 | activeCart(request: Request, response: Response) {
38 | const resource = this.repository.getActiveCart(request.params.projectKey);
39 | if (!resource) {
40 | response.status(404).send({
41 | statusCode: 404,
42 | message: "No active cart exists.",
43 | errors: [
44 | {
45 | code: "ResourceNotFound",
46 | message: "No active cart exists.",
47 | },
48 | ],
49 | });
50 | return;
51 | }
52 | response.status(200).send(resource);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/services/my-order.ts:
--------------------------------------------------------------------------------
1 | import { Router } from "express";
2 | import type { MyOrderRepository } from "../repositories/my-order";
3 | import AbstractService from "./abstract";
4 |
5 | export class MyOrderService extends AbstractService {
6 | public repository: MyOrderRepository;
7 |
8 | constructor(parent: Router, repository: MyOrderRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "me";
15 | }
16 |
17 | registerRoutes(parent: Router) {
18 | // Overwrite this function to be able to handle /me/active-cart path.
19 | const basePath = this.getBasePath();
20 | const router = Router({ mergeParams: true });
21 |
22 | this.extraRoutes(router);
23 |
24 | router.get("/orders/", this.get.bind(this));
25 | router.get("/orders/:id", this.getWithId.bind(this));
26 |
27 | router.delete("/orders/:id", this.deleteWithId.bind(this));
28 |
29 | router.post("/orders/", this.post.bind(this));
30 | router.post("/orders/:id", this.postWithId.bind(this));
31 |
32 | parent.use(`/${basePath}`, router);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/services/my-payment.test.ts:
--------------------------------------------------------------------------------
1 | import type { MyPaymentDraft } from "@commercetools/platform-sdk";
2 | import supertest from "supertest";
3 | import { beforeEach, describe, expect, test } from "vitest";
4 | import { CommercetoolsMock } from "../index";
5 |
6 | const ctMock = new CommercetoolsMock();
7 |
8 | describe("MyPayment", () => {
9 | beforeEach(async () => {
10 | const response = await supertest(ctMock.app)
11 | .post("/dummy/types")
12 | .send({
13 | key: "custom-payment",
14 | name: {
15 | "nl-NL": "custom-payment",
16 | },
17 | resourceTypeIds: ["payment"],
18 | });
19 | expect(response.status).toBe(201);
20 | });
21 |
22 | test("Create payment", async () => {
23 | const draft: MyPaymentDraft = {
24 | amountPlanned: { currencyCode: "EUR", centAmount: 1337 },
25 | custom: {
26 | type: { typeId: "type", key: "custom-payment" },
27 | fields: {
28 | foo: "bar",
29 | },
30 | },
31 | };
32 | const response = await supertest(ctMock.app)
33 | .post("/dummy/me/payments")
34 | .send(draft);
35 |
36 | expect(response.status).toBe(201);
37 | expect(response.body).toEqual({
38 | id: expect.anything(),
39 | createdAt: expect.anything(),
40 | lastModifiedAt: expect.anything(),
41 | version: 1,
42 | amountPlanned: {
43 | type: "centPrecision",
44 | fractionDigits: 2,
45 | currencyCode: "EUR",
46 | centAmount: 1337,
47 | },
48 | paymentStatus: {},
49 | transactions: [],
50 | interfaceInteractions: [],
51 | custom: {
52 | type: { typeId: "type", id: expect.anything() },
53 | fields: { foo: "bar" },
54 | },
55 | });
56 | });
57 | test("Get payment", async () => {
58 | const draft: MyPaymentDraft = {
59 | amountPlanned: { currencyCode: "EUR", centAmount: 1337 },
60 | custom: {
61 | type: { typeId: "type", key: "custom-payment" },
62 | fields: {
63 | foo: "bar",
64 | },
65 | },
66 | };
67 | const createResponse = await supertest(ctMock.app)
68 | .post("/dummy/me/payments")
69 | .send(draft);
70 |
71 | const response = await supertest(ctMock.app).get(
72 | `/dummy/me/payments/${createResponse.body.id}`,
73 | );
74 |
75 | expect(response.status).toBe(200);
76 | expect(response.body).toEqual(createResponse.body);
77 | });
78 | });
79 |
--------------------------------------------------------------------------------
/src/services/my-payment.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { PaymentRepository } from "../repositories/payment";
3 | import AbstractService from "./abstract";
4 |
5 | export class MyPaymentService extends AbstractService {
6 | public repository: PaymentRepository;
7 |
8 | constructor(parent: Router, repository: PaymentRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "me/payments";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/my-shopping-list.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { ShoppingListRepository } from "../repositories/shopping-list";
3 | import AbstractService from "./abstract";
4 |
5 | export class MyShoppingListService extends AbstractService {
6 | public repository: ShoppingListRepository;
7 |
8 | constructor(parent: Router, repository: ShoppingListRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "me/shopping-lists";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/order.ts:
--------------------------------------------------------------------------------
1 | import type { Request, Response, Router } from "express";
2 | import { getRepositoryContext } from "../repositories/helpers";
3 | import type { OrderRepository } from "../repositories/order/index";
4 | import AbstractService from "./abstract";
5 |
6 | export class OrderService extends AbstractService {
7 | public repository: OrderRepository;
8 |
9 | constructor(parent: Router, repository: OrderRepository) {
10 | super(parent);
11 | this.repository = repository;
12 | }
13 |
14 | getBasePath() {
15 | return "orders";
16 | }
17 |
18 | extraRoutes(router: Router) {
19 | router.post("/import", this.import.bind(this));
20 | router.get(
21 | "/order-number=:orderNumber",
22 | this.getWithOrderNumber.bind(this),
23 | );
24 | }
25 |
26 | import(request: Request, response: Response) {
27 | const importDraft = request.body;
28 | const resource = this.repository.import(
29 | getRepositoryContext(request),
30 | importDraft,
31 | );
32 | response.status(200).send(resource);
33 | }
34 |
35 | getWithOrderNumber(request: Request, response: Response) {
36 | const orderNumber = request.params.orderNumber;
37 | const resource = this.repository.getWithOrderNumber(
38 | getRepositoryContext(request),
39 | orderNumber,
40 |
41 | // @ts-ignore
42 | request.query,
43 | );
44 | if (resource) {
45 | response.status(200).send(resource);
46 | return;
47 | }
48 | response.status(404).send({
49 | statusCode: 404,
50 | message: `The Resource with key '${orderNumber}' was not found.`,
51 | errors: [
52 | {
53 | code: "ResourceNotFound",
54 | message: `The Resource with key '${orderNumber}' was not found.`,
55 | },
56 | ],
57 | });
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/services/payment.test.ts:
--------------------------------------------------------------------------------
1 | import type { PaymentDraft } from "@commercetools/platform-sdk";
2 | import supertest from "supertest";
3 | import { beforeEach, describe, expect, test } from "vitest";
4 | import { CommercetoolsMock } from "../index";
5 |
6 | const ctMock = new CommercetoolsMock();
7 |
8 | describe("Payment", () => {
9 | beforeEach(async () => {
10 | const response = await supertest(ctMock.app)
11 | .post("/dummy/types")
12 | .send({
13 | key: "custom-payment",
14 | name: {
15 | "nl-NL": "custom-payment",
16 | },
17 | resourceTypeIds: ["payment"],
18 | });
19 | expect(response.status).toBe(201);
20 | });
21 |
22 | test("Create payment", async () => {
23 | const draft: PaymentDraft = {
24 | amountPlanned: { currencyCode: "EUR", centAmount: 1337 },
25 | custom: {
26 | type: { typeId: "type", key: "custom-payment" },
27 | fields: {
28 | foo: "bar",
29 | },
30 | },
31 | };
32 | const response = await supertest(ctMock.app)
33 | .post("/dummy/payments")
34 | .send(draft);
35 |
36 | expect(response.status).toBe(201);
37 | expect(response.body).toEqual({
38 | id: expect.anything(),
39 | createdAt: expect.anything(),
40 | lastModifiedAt: expect.anything(),
41 | version: 1,
42 | amountPlanned: {
43 | type: "centPrecision",
44 | fractionDigits: 2,
45 | currencyCode: "EUR",
46 | centAmount: 1337,
47 | },
48 | paymentStatus: {},
49 | transactions: [],
50 | interfaceInteractions: [],
51 | custom: {
52 | type: { typeId: "type", id: expect.anything() },
53 | fields: { foo: "bar" },
54 | },
55 | });
56 | });
57 | test("Get payment", async () => {
58 | const draft: PaymentDraft = {
59 | amountPlanned: { currencyCode: "EUR", centAmount: 1337 },
60 | custom: {
61 | type: { typeId: "type", key: "custom-payment" },
62 | fields: {
63 | foo: "bar",
64 | },
65 | },
66 | };
67 | const createResponse = await supertest(ctMock.app)
68 | .post("/dummy/payments")
69 | .send(draft);
70 |
71 | const response = await supertest(ctMock.app).get(
72 | `/dummy/payments/${createResponse.body.id}`,
73 | );
74 |
75 | expect(response.status).toBe(200);
76 | expect(response.body).toEqual(createResponse.body);
77 | });
78 | });
79 |
--------------------------------------------------------------------------------
/src/services/payment.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { PaymentRepository } from "../repositories/payment";
3 | import AbstractService from "./abstract";
4 |
5 | export class PaymentService extends AbstractService {
6 | public repository: PaymentRepository;
7 |
8 | constructor(parent: Router, repository: PaymentRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "payments";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/product-discount.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { ProductDiscountRepository } from "../repositories/product-discount";
3 | import AbstractService from "./abstract";
4 |
5 | export class ProductDiscountService extends AbstractService {
6 | public repository: ProductDiscountRepository;
7 |
8 | constructor(parent: Router, repository: ProductDiscountRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "product-discounts";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/product-projection.ts:
--------------------------------------------------------------------------------
1 | import type { Request, Response, Router } from "express";
2 | import { queryParamsArray, queryParamsValue } from "../helpers";
3 | import { getRepositoryContext } from "../repositories/helpers";
4 | import type {
5 | ProductProjectionQueryParams,
6 | ProductProjectionRepository,
7 | } from "./../repositories/product-projection";
8 | import AbstractService from "./abstract";
9 |
10 | export class ProductProjectionService extends AbstractService {
11 | public repository: ProductProjectionRepository;
12 |
13 | constructor(parent: Router, repository: ProductProjectionRepository) {
14 | super(parent);
15 | this.repository = repository;
16 | }
17 |
18 | getBasePath() {
19 | return "product-projections";
20 | }
21 |
22 | extraRoutes(router: Router) {
23 | router.get("/search", this.search.bind(this));
24 | }
25 |
26 | get(request: Request, response: Response) {
27 | const limit = this._parseParam(request.query.limit);
28 | const offset = this._parseParam(request.query.offset);
29 |
30 | const result = this.repository.query(getRepositoryContext(request), {
31 | ...request.query,
32 | expand: this._parseParam(request.query.expand),
33 | where: this._parseParam(request.query.where),
34 | limit: limit !== undefined ? Number(limit) : undefined,
35 | offset: offset !== undefined ? Number(offset) : undefined,
36 | });
37 | response.status(200).send(result);
38 | }
39 |
40 | search(request: Request, response: Response) {
41 | const query = request.query;
42 | const searchParams: ProductProjectionQueryParams = {
43 | filter: queryParamsArray(query.filter),
44 | "filter.query": queryParamsArray(query["filter.query"]),
45 | facet: queryParamsArray(query.facet),
46 | expand: queryParamsArray(query.expand),
47 | staged: queryParamsValue(query.staged) === "true",
48 | localeProjection: queryParamsValue(query.localeProjection),
49 | storeProjection: queryParamsValue(query.storeProjection),
50 | priceChannel: queryParamsValue(query.priceChannel),
51 | priceCountry: queryParamsValue(query.priceCountry),
52 | priceCurrency: queryParamsValue(query.priceCurrency),
53 | priceCustomerGroup: queryParamsValue(query.priceCustomerGroup),
54 | offset: query.offset ? Number(queryParamsValue(query.offset)) : undefined,
55 | limit: query.limit ? Number(queryParamsValue(query.limit)) : undefined,
56 | };
57 | const resource = this.repository.search(
58 | getRepositoryContext(request),
59 | searchParams,
60 | );
61 | response.status(200).send(resource);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/services/product-selection.test.ts:
--------------------------------------------------------------------------------
1 | import type { ProductSelectionDraft } from "@commercetools/platform-sdk";
2 | import supertest from "supertest";
3 | import { describe, expect, test } from "vitest";
4 | import { CommercetoolsMock } from "../index";
5 |
6 | const ctMock = new CommercetoolsMock();
7 |
8 | describe("product-selection", () => {
9 | test("Create product selection", async () => {
10 | const draft: ProductSelectionDraft = {
11 | name: {
12 | en: "foo",
13 | },
14 | key: "foo",
15 | };
16 | const response = await supertest(ctMock.app)
17 | .post("/dummy/product-selections")
18 | .send(draft);
19 |
20 | expect(response.status).toBe(201);
21 |
22 | expect(response.body).toEqual({
23 | createdAt: expect.anything(),
24 | id: expect.anything(),
25 | lastModifiedAt: expect.anything(),
26 | name: {
27 | en: "foo",
28 | },
29 | key: "foo",
30 | version: 1,
31 | productCount: 0,
32 | mode: "Individual",
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/src/services/product-selection.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { ProductSelectionRepository } from "../repositories/product-selection";
3 | import AbstractService from "./abstract";
4 |
5 | export class ProductSelectionService extends AbstractService {
6 | public repository: ProductSelectionRepository;
7 |
8 | constructor(parent: Router, repository: ProductSelectionRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "product-selections";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/product-type.test.ts:
--------------------------------------------------------------------------------
1 | import type { ProductTypeDraft } from "@commercetools/platform-sdk";
2 | import supertest from "supertest";
3 | import { describe, expect, test } from "vitest";
4 | import { CommercetoolsMock } from "../index";
5 |
6 | const ctMock = new CommercetoolsMock();
7 |
8 | describe("Product type", () => {
9 | test("Create product type", async () => {
10 | const draft: ProductTypeDraft = {
11 | name: "foo",
12 | description: "bar",
13 | attributes: [
14 | {
15 | name: "name",
16 | type: { name: "boolean" },
17 | label: { "nl-NL": "bar" },
18 | isRequired: false,
19 | },
20 | ],
21 | };
22 | const response = await supertest(ctMock.app)
23 | .post("/dummy/product-types")
24 | .send(draft);
25 |
26 | expect(response.status).toBe(201);
27 |
28 | expect(response.body).toEqual({
29 | attributes: [
30 | {
31 | attributeConstraint: "None",
32 | inputHint: "SingleLine",
33 | isRequired: false,
34 | isSearchable: true,
35 | label: {
36 | "nl-NL": "bar",
37 | },
38 | name: "name",
39 | type: {
40 | name: "boolean",
41 | },
42 | },
43 | ],
44 | createdAt: expect.anything(),
45 | description: "bar",
46 | id: expect.anything(),
47 | lastModifiedAt: expect.anything(),
48 | name: "foo",
49 | version: 1,
50 | });
51 | });
52 |
53 | test("Get product type", async () => {
54 | const draft: ProductTypeDraft = {
55 | name: "foo",
56 | description: "bar",
57 | };
58 | const createResponse = await supertest(ctMock.app)
59 | .post("/dummy/product-types")
60 | .send(draft);
61 |
62 | expect(createResponse.status).toBe(201);
63 |
64 | const response = await supertest(ctMock.app).get(
65 | `/dummy/product-types/${createResponse.body.id}`,
66 | );
67 |
68 | expect(response.status).toBe(200);
69 | expect(response.body).toEqual(createResponse.body);
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/src/services/product-type.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { ProductTypeRepository } from "../repositories/product-type";
3 | import AbstractService from "./abstract";
4 |
5 | export class ProductTypeService extends AbstractService {
6 | public repository: ProductTypeRepository;
7 |
8 | constructor(parent: Router, repository: ProductTypeRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "product-types";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/product.ts:
--------------------------------------------------------------------------------
1 | import type { Request, Response, Router } from "express";
2 | import { getRepositoryContext } from "~src/repositories/helpers";
3 | import type { ProductRepository } from "../repositories/product";
4 | import AbstractService from "./abstract";
5 |
6 | export class ProductService extends AbstractService {
7 | public repository: ProductRepository;
8 |
9 | constructor(parent: Router, repository: ProductRepository) {
10 | super(parent);
11 | this.repository = repository;
12 | }
13 |
14 | getBasePath() {
15 | return "products";
16 | }
17 |
18 | extraRoutes(router: Router) {
19 | router.post("/search", this.search.bind(this));
20 | }
21 |
22 | search(request: Request, response: Response) {
23 | const searchBody = request.body;
24 | const resource = this.repository.search(
25 | getRepositoryContext(request),
26 | searchBody,
27 | );
28 | response.status(200).send(resource);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/services/project.test.ts:
--------------------------------------------------------------------------------
1 | import type { Project } from "@commercetools/platform-sdk";
2 | import supertest from "supertest";
3 | import { describe, expect, test } from "vitest";
4 | import { CommercetoolsMock } from "../index";
5 |
6 | const ctMock = new CommercetoolsMock();
7 |
8 | describe("Project", () => {
9 | test("Get project by key", async () => {
10 | const response = await supertest(ctMock.app).get("/dummy/");
11 |
12 | expect(response.status).toBe(200);
13 | expect(response.body).toEqual({
14 | version: 1,
15 | carts: {
16 | countryTaxRateFallbackEnabled: false,
17 | deleteDaysAfterLastModification: 90,
18 | },
19 | countries: [],
20 | createdAt: "2018-10-04T11:32:12.603Z",
21 | currencies: [],
22 | key: "dummy",
23 | languages: [],
24 | messages: {
25 | deleteDaysAfterCreation: 15,
26 | enabled: false,
27 | },
28 | name: "",
29 | searchIndexing: {
30 | customers: {
31 | status: "Deactivated",
32 | },
33 | orders: {
34 | status: "Deactivated",
35 | },
36 | products: {
37 | status: "Deactivated",
38 | },
39 | productsSearch: {
40 | status: "Deactivated",
41 | },
42 | },
43 | trialUntil: "2018-12",
44 | } as Project);
45 | });
46 |
47 | test("Post empty update ", async () => {
48 | const response = await supertest(ctMock.app).post("/dummy/");
49 | expect(response.statusCode).toBe(400);
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/src/services/project.ts:
--------------------------------------------------------------------------------
1 | import type { Update } from "@commercetools/platform-sdk";
2 | import type { Request, Response, Router } from "express";
3 | import { updateRequestSchema } from "~src/schemas/update-request";
4 | import { validateData } from "~src/validate";
5 | import { getRepositoryContext } from "../repositories/helpers";
6 | import type { ProjectRepository } from "../repositories/project";
7 |
8 | export class ProjectService {
9 | public repository: ProjectRepository;
10 |
11 | constructor(parent: Router, repository: ProjectRepository) {
12 | this.repository = repository;
13 | this.registerRoutes(parent);
14 | }
15 |
16 | registerRoutes(parent: Router) {
17 | parent.get("", this.get.bind(this));
18 | parent.post("", this.post.bind(this));
19 | }
20 |
21 | get(request: Request, response: Response) {
22 | const project = this.repository.get(getRepositoryContext(request));
23 | response.status(200).send(project);
24 | }
25 |
26 | post(request: Request, response: Response) {
27 | const updateRequest = validateData(
28 | request.body,
29 | updateRequestSchema,
30 | );
31 | const project = this.repository.get(getRepositoryContext(request));
32 |
33 | if (!project) {
34 | response.status(404).send({ statusCode: 404 });
35 | return;
36 | }
37 |
38 | const updatedResource = this.repository.processUpdateActions(
39 | getRepositoryContext(request),
40 | project,
41 | updateRequest.version,
42 | updateRequest.actions,
43 | );
44 |
45 | response.status(200).send(updatedResource);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/services/quote-request.test.ts:
--------------------------------------------------------------------------------
1 | import supertest from "supertest";
2 | import { afterEach, describe, expect, it } from "vitest";
3 | import { customerDraftFactory } from "~src/testing/customer";
4 | import { CommercetoolsMock } from "../index";
5 |
6 | describe("Quote Request Create", () => {
7 | const ctMock = new CommercetoolsMock();
8 |
9 | afterEach(() => {
10 | ctMock.clear();
11 | });
12 |
13 | it("should create a quote request", async () => {
14 | const customer = await customerDraftFactory(ctMock).create();
15 | let response = await supertest(ctMock.app)
16 | .post("/dummy/carts")
17 | .send({
18 | currency: "EUR",
19 | customerId: customer.id,
20 | custom: {
21 | type: {
22 | key: "my-cart",
23 | },
24 | fields: {
25 | description: "example description",
26 | },
27 | },
28 | });
29 | expect(response.status).toBe(201);
30 | const cart = response.body;
31 |
32 | response = await supertest(ctMock.app)
33 | .post("/dummy/quote-requests")
34 | .send({
35 | cart: {
36 | typeId: "cart",
37 | id: cart.id,
38 | },
39 | cartVersion: cart.version,
40 | });
41 | expect(response.status).toBe(201);
42 | const quote = response.body;
43 |
44 | expect(quote.cart).toEqual({
45 | typeId: "cart",
46 | id: cart.id,
47 | });
48 |
49 | response = await supertest(ctMock.app)
50 | .get(`/dummy/quote-requests/${quote.id}`)
51 | .send();
52 |
53 | const quoteResult = response.body;
54 | expect(quoteResult.cart).toEqual({
55 | typeId: "cart",
56 | id: cart.id,
57 | });
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/src/services/quote-request.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { QuoteRequestRepository } from "~src/repositories/quote-request";
3 | import AbstractService from "./abstract";
4 |
5 | export class QuoteRequestService extends AbstractService {
6 | public repository: QuoteRequestRepository;
7 |
8 | constructor(parent: Router, repository: QuoteRequestRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "quote-requests";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/quote-staged.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { StagedQuoteRepository } from "~src/repositories/quote-staged";
3 | import AbstractService from "./abstract";
4 |
5 | export class StagedQuoteService extends AbstractService {
6 | public repository: StagedQuoteRepository;
7 |
8 | constructor(parent: Router, repository: StagedQuoteRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "staged-quotes";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/quote.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { QuoteRepository } from "~src/repositories/quote";
3 | import AbstractService from "./abstract";
4 |
5 | export class QuoteService extends AbstractService {
6 | public repository: QuoteRepository;
7 |
8 | constructor(parent: Router, repository: QuoteRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "quotes";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/reviews.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { ReviewRepository } from "../repositories/review";
3 | import AbstractService from "./abstract";
4 |
5 | export class ReviewService extends AbstractService {
6 | public repository: ReviewRepository;
7 |
8 | constructor(parent: Router, repository: ReviewRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "reviews";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/shipping-method.ts:
--------------------------------------------------------------------------------
1 | import type { Request, Response, Router } from "express";
2 | import { queryParamsValue } from "../helpers";
3 | import { getRepositoryContext } from "../repositories/helpers";
4 | import type { ShippingMethodRepository } from "../repositories/shipping-method";
5 | import AbstractService from "./abstract";
6 |
7 | export class ShippingMethodService extends AbstractService {
8 | public repository: ShippingMethodRepository;
9 |
10 | constructor(parent: Router, repository: ShippingMethodRepository) {
11 | super(parent);
12 | this.repository = repository;
13 | this.registerRoutes(parent);
14 | }
15 |
16 | getBasePath() {
17 | return "shipping-methods";
18 | }
19 |
20 | extraRoutes(parent: Router) {
21 | parent.get("/matching-cart", this.matchingCart.bind(this));
22 | }
23 |
24 | matchingCart(request: Request, response: Response) {
25 | const cartId = queryParamsValue(request.query.cartId);
26 | if (!cartId) {
27 | response.status(400).send();
28 | return;
29 | }
30 | const result = this.repository.matchingCart(
31 | getRepositoryContext(request),
32 | cartId,
33 | {
34 | expand: this._parseParam(request.query.expand),
35 | },
36 | );
37 | response.status(200).send(result);
38 | return;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/services/shopping-list.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { ShoppingListRepository } from "../repositories/shopping-list";
3 | import AbstractService from "./abstract";
4 |
5 | export class ShoppingListService extends AbstractService {
6 | public repository: ShoppingListRepository;
7 |
8 | constructor(parent: Router, repository: ShoppingListRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "shopping-lists";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/standalone-price.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { StandAlonePriceRepository } from "../repositories/standalone-price";
3 | import AbstractService from "./abstract";
4 |
5 | export class StandAlonePriceService extends AbstractService {
6 | public repository: StandAlonePriceRepository;
7 |
8 | constructor(parent: Router, repository: StandAlonePriceRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "standalone-prices";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/state.test.ts:
--------------------------------------------------------------------------------
1 | import type { StateDraft } from "@commercetools/platform-sdk";
2 | import supertest from "supertest";
3 | import { describe, expect, test } from "vitest";
4 | import { CommercetoolsMock } from "../index";
5 |
6 | const ctMock = new CommercetoolsMock();
7 |
8 | describe("State", () => {
9 | test("Create state", async () => {
10 | const draft: StateDraft = {
11 | key: "foo",
12 | type: "PaymentState",
13 | };
14 | const response = await supertest(ctMock.app)
15 | .post("/dummy/states")
16 | .send(draft);
17 |
18 | expect(response.status).toBe(201);
19 |
20 | expect(response.body).toEqual({
21 | builtIn: false,
22 | createdAt: expect.anything(),
23 | id: expect.anything(),
24 | initial: false,
25 | key: "foo",
26 | lastModifiedAt: expect.anything(),
27 | transitions: [],
28 | type: "PaymentState",
29 | version: 1,
30 | });
31 | });
32 |
33 | test("Get state", async () => {
34 | const draft: StateDraft = {
35 | key: "foo",
36 | type: "PaymentState",
37 | };
38 | const createResponse = await supertest(ctMock.app)
39 | .post("/dummy/states")
40 | .send(draft);
41 |
42 | expect(createResponse.status).toBe(201);
43 |
44 | const response = await supertest(ctMock.app).get(
45 | `/dummy/states/${createResponse.body.id}`,
46 | );
47 |
48 | expect(response.status).toBe(200);
49 | expect(response.body).toEqual(createResponse.body);
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/src/services/state.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { StateRepository } from "../repositories/state";
3 | import AbstractService from "./abstract";
4 |
5 | export class StateService extends AbstractService {
6 | public repository: StateRepository;
7 |
8 | constructor(parent: Router, repository: StateRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "states";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/store.test.ts:
--------------------------------------------------------------------------------
1 | import type { Store } from "@commercetools/platform-sdk";
2 | import supertest from "supertest";
3 | import { describe, expect, test } from "vitest";
4 | import { CommercetoolsMock } from "../index";
5 |
6 | const ctMock = new CommercetoolsMock();
7 |
8 | describe("Store", () => {
9 | test("Get store by key", async () => {
10 | ctMock.project("dummy").add("store", {
11 | id: "fake-store",
12 | version: 1,
13 | createdAt: "",
14 | lastModifiedAt: "",
15 | key: "STOREKEY",
16 | countries: [],
17 | languages: [],
18 | distributionChannels: [],
19 | supplyChannels: [],
20 | productSelections: [],
21 | });
22 |
23 | const response = await supertest(ctMock.app).get(
24 | "/dummy/stores/key=STOREKEY",
25 | );
26 |
27 | expect(response.status).toBe(200);
28 | expect(response.body).toEqual({
29 | version: 1,
30 | createdAt: "",
31 | id: "fake-store",
32 | key: "STOREKEY",
33 | lastModifiedAt: "",
34 | countries: [],
35 | languages: [],
36 | distributionChannels: [],
37 | supplyChannels: [],
38 | productSelections: [],
39 | } as Store);
40 | });
41 |
42 | test("Get store by 404 when not found by key", async () => {
43 | ctMock.project("dummy").add("store", {
44 | id: "fake-store",
45 | version: 1,
46 | createdAt: "",
47 | lastModifiedAt: "",
48 | key: "STOREKEY",
49 | countries: [],
50 | languages: [],
51 | distributionChannels: [],
52 | supplyChannels: [],
53 | productSelections: [],
54 | });
55 |
56 | const response = await supertest(ctMock.app).get(
57 | "/dummy/stores/key=DOESNOTEXIST",
58 | );
59 |
60 | expect(response.status).toBe(404);
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/src/services/store.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { StoreRepository } from "../repositories/store";
3 | import AbstractService from "./abstract";
4 |
5 | export class StoreService extends AbstractService {
6 | public repository: StoreRepository;
7 |
8 | constructor(parent: Router, repository: StoreRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "stores";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/subscription.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { SubscriptionRepository } from "../repositories/subscription";
3 | import AbstractService from "./abstract";
4 |
5 | export class SubscriptionService extends AbstractService {
6 | public repository: SubscriptionRepository;
7 |
8 | constructor(parent: Router, repository: SubscriptionRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "subscriptions";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/tax-category.test.ts:
--------------------------------------------------------------------------------
1 | import type { TaxCategoryDraft } from "@commercetools/platform-sdk";
2 | import supertest from "supertest";
3 | import { afterEach, describe, expect, test } from "vitest";
4 | import { CommercetoolsMock } from "../index";
5 |
6 | const ctMock = new CommercetoolsMock();
7 |
8 | describe("Tax Category", () => {
9 | afterEach(() => {
10 | ctMock.clear();
11 | });
12 | test("Create tax category", async () => {
13 | const draft: TaxCategoryDraft = {
14 | name: "foo",
15 | key: "standard",
16 | rates: [],
17 | };
18 | const response = await supertest(ctMock.app)
19 | .post("/dummy/tax-categories")
20 | .send(draft);
21 |
22 | expect(response.status).toBe(201);
23 |
24 | expect(response.body).toEqual({
25 | createdAt: expect.anything(),
26 | id: expect.anything(),
27 | lastModifiedAt: expect.anything(),
28 | name: "foo",
29 | rates: [],
30 | key: "standard",
31 | version: 1,
32 | });
33 | });
34 |
35 | test("Get tax category", async () => {
36 | const draft: TaxCategoryDraft = {
37 | name: "foo",
38 | key: "standard",
39 | rates: [],
40 | };
41 | const createResponse = await supertest(ctMock.app)
42 | .post("/dummy/tax-categories")
43 | .send(draft);
44 |
45 | expect(createResponse.status).toBe(201);
46 |
47 | const response = await supertest(ctMock.app).get(
48 | `/dummy/tax-categories/${createResponse.body.id}`,
49 | );
50 |
51 | expect(response.status).toBe(200);
52 | expect(response.body).toEqual(createResponse.body);
53 | });
54 |
55 | test("Get tax category with key", async () => {
56 | const draft: TaxCategoryDraft = {
57 | name: "foo",
58 | key: "standard",
59 | rates: [],
60 | };
61 | const createResponse = await supertest(ctMock.app)
62 | .post("/dummy/tax-categories")
63 | .send(draft);
64 |
65 | expect(createResponse.status).toBe(201);
66 |
67 | const response = await supertest(ctMock.app)
68 | .get("/dummy/tax-categories/")
69 | .query({ where: `key="${createResponse.body.key}"` });
70 |
71 | expect(response.status).toBe(200);
72 | expect(response.body).toEqual({
73 | count: 1,
74 | limit: 20,
75 | offset: 0,
76 | total: 1,
77 | results: [createResponse.body],
78 | });
79 | });
80 | });
81 |
--------------------------------------------------------------------------------
/src/services/tax-category.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { TaxCategoryRepository } from "../repositories/tax-category";
3 | import AbstractService from "./abstract";
4 |
5 | export class TaxCategoryService extends AbstractService {
6 | public repository: TaxCategoryRepository;
7 |
8 | constructor(parent: Router, repository: TaxCategoryRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "tax-categories";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/type.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { TypeRepository } from "../repositories/type";
3 | import AbstractService from "./abstract";
4 |
5 | export class TypeService extends AbstractService {
6 | public repository: TypeRepository;
7 |
8 | constructor(parent: Router, repository: TypeRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "types";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/zone.ts:
--------------------------------------------------------------------------------
1 | import type { Router } from "express";
2 | import type { ZoneRepository } from "../repositories/zone";
3 | import AbstractService from "./abstract";
4 |
5 | export class ZoneService extends AbstractService {
6 | public repository: ZoneRepository;
7 |
8 | constructor(parent: Router, repository: ZoneRepository) {
9 | super(parent);
10 | this.repository = repository;
11 | }
12 |
13 | getBasePath() {
14 | return "zones";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/storage/abstract.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | BaseResource,
3 | Project,
4 | QueryParam,
5 | ResourceIdentifier,
6 | } from "@commercetools/platform-sdk";
7 | import type {
8 | PagedQueryResponseMap,
9 | ResourceMap,
10 | ResourceType,
11 | } from "../types";
12 |
13 | export type GetParams = {
14 | expand?: string[];
15 | };
16 |
17 | export type QueryParams = {
18 | expand?: string | string[];
19 | sort?: string | string[];
20 | limit?: number;
21 | offset?: number;
22 | withTotal?: boolean;
23 | where?: string | string[];
24 | [key: string]: QueryParam;
25 | };
26 |
27 | export abstract class AbstractStorage {
28 | abstract clear(): void;
29 |
30 | abstract all