feat(medusa): Convert SwapService to TypeScript (#2000)

**What**
- refactor swap service to typescript
- reimplement legacy methods
- use enums instead of magic strings

RESOLVES CORE-396

Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Frane PolićandOliver Windall Juhl authored and GitHub committed 2022-09-05 13:37:47 +00:00
1 parent 546a963f7b
commit ba6416f095
14 files changed
+609 -599

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/medusa": patch
---
Convert SwapService to TypeScript
@@ -178,7 +178,6 @@ describe("medusa-plugin-sendgrid", () => {
order: { order: {
display_id: expect.any(Number), display_id: expect.any(Number),
id: expect.any(String), id: expect.any(String),
display_id: expect.any(Number),
created_at: expect.any(Date), created_at: expect.any(Date),
updated_at: expect.any(Date), updated_at: expect.any(Date),
customer_id: expect.any(String), customer_id: expect.any(String),
@@ -36,7 +36,7 @@ import { validator } from "../../../../utils/validator"
* items: * items:
* type: string * type: string
* no_notification: * no_notification:
* description: If set to true no notification will be send related to this Claim. * description: If set to true no notification will be sent related to this Claim.
* type: boolean * type: boolean
* tags: * tags:
* - Swap * - Swap
@@ -67,7 +67,7 @@ export default async (req, res) => {
export class AdminPostOrdersOrderSwapsSwapFulfillmentsReq { export class AdminPostOrdersOrderSwapsSwapFulfillmentsReq {
@IsObject() @IsObject()
@IsOptional() @IsOptional()
metadata?: object metadata?: Record<string, unknown>
@IsBoolean() @IsBoolean()
@IsOptional() @IsOptional()
@@ -1,8 +1,10 @@
import { Type } from "class-transformer"
import { IsInt, IsOptional } from "class-validator" import { IsInt, IsOptional } from "class-validator"
import { SwapService } from "../../../../services" import { SwapService } from "../../../../services"
import { Type } from "class-transformer"
import { validator } from "../../../../utils/validator" import { validator } from "../../../../utils/validator"
import { FindConfig } from "../../../../types/common"
import { Swap } from "../../../../models"
/** /**
* @oas [get] /swaps * @oas [get] /swaps
@@ -43,7 +45,7 @@ export default async (req, res) => {
const selector = {} const selector = {}
const listConfig = { const listConfig: FindConfig<Swap> = {
skip: offset, skip: offset,
take: limit, take: limit,
order: { created_at: "DESC" }, order: { created_at: "DESC" },
@@ -1,6 +1,8 @@
import { Swap } from "./../../../../"
import { Router } from "express" import { Router } from "express"
import { Swap } from "./../../../../"
import middlewares from "../../../middlewares" import middlewares from "../../../middlewares"
import { FindConfig } from "../../../../types/common"
const route = Router() const route = Router()
@@ -27,7 +29,7 @@ export const defaultStoreSwapRelations = [
"shipping_methods", "shipping_methods",
"cart", "cart",
] ]
export const defaultStoreSwapFields = [ export const defaultStoreSwapFields: FindConfig<Swap>["select"] = [
"id", "id",
"fulfillment_status", "fulfillment_status",
"payment_status", "payment_status",
@@ -0,0 +1,33 @@
import { MigrationInterface, QueryRunner } from "typeorm"
export class swapFulfillmentStatusRequiresAction1661863940645
implements MigrationInterface
{
name = "swapFulfillmentStatusRequiresAction1661863940645"
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TYPE "swap_fulfillment_status_enum" RENAME TO "swap_fulfillment_status_enum_old"`
)
await queryRunner.query(
`CREATE TYPE "swap_fulfillment_status_enum" AS ENUM('not_fulfilled', 'fulfilled', 'shipped', 'partially_shipped', 'canceled', 'requires_action')`
)
await queryRunner.query(
`ALTER TABLE "swap" ALTER COLUMN "fulfillment_status" TYPE "swap_fulfillment_status_enum" USING "fulfillment_status"::"text"::"swap_fulfillment_status_enum"`
)
await queryRunner.query(`DROP TYPE "swap_fulfillment_status_enum_old"`)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "swap_fulfillment_status_enum_old" AS ENUM('not_fulfilled', 'fulfilled', 'shipped', 'canceled', 'requires_action')`
)
await queryRunner.query(
`ALTER TABLE "swap" ALTER COLUMN "fulfillment_status" TYPE "swap_fulfillment_status_enum_old" USING "fulfillment_status"::"text"::"swap_fulfillment_status_enum_old"`
)
await queryRunner.query(`DROP TYPE "swap_fulfillment_status_enum"`)
await queryRunner.query(
`ALTER TYPE "swap_fulfillment_status_enum_old" RENAME TO "swap_fulfillment_status_enum"`
)
}
}
+2 -1
View File
@@ -25,6 +25,7 @@ export enum SwapFulfillmentStatus {
NOT_FULFILLED = "not_fulfilled", NOT_FULFILLED = "not_fulfilled",
FULFILLED = "fulfilled", FULFILLED = "fulfilled",
SHIPPED = "shipped", SHIPPED = "shipped",
PARTIALLY_SHIPPED = "partially_shipped",
CANCELED = "canceled", CANCELED = "canceled",
REQUIRES_ACTION = "requires_action", REQUIRES_ACTION = "requires_action",
} }
@@ -190,7 +191,7 @@ export class Swap extends SoftDeletableEntity {
* description: Available if the relation `shipping_address` is expanded. * description: Available if the relation `shipping_address` is expanded.
* $ref: "#/components/schemas/address" * $ref: "#/components/schemas/address"
* shipping_methods: * shipping_methods:
* description: The Shipping Methods used to fulfill the addtional items purchased. Available if the relation `shipping_methods` is expanded. * description: The Shipping Methods used to fulfill the additional items purchased. Available if the relation `shipping_methods` is expanded.
* type: array * type: array
* items: * items:
* $ref: "#/components/schemas/shipping_method" * $ref: "#/components/schemas/shipping_method"
@@ -124,82 +124,6 @@ describe("CartService", () => {
}) })
}) })
describe("deleteMetadata", () => {
const cartRepository = MockRepository({
findOne: (id) => {
if (id === "empty") {
return Promise.resolve({
metadata: {},
})
}
return Promise.resolve({
metadata: {
existing: "something",
},
})
},
})
const cartService = new CartService({
manager: MockManager,
totalsService,
cartRepository,
eventBusService,
featureFlagRouter: new FlagRouter({}),
})
beforeEach(() => {
jest.clearAllMocks()
})
it("calls updateOne with correct params", async () => {
const id = "testCart"
await cartService.deleteMetadata(id, "existing")
expect(eventBusService.emit).toHaveBeenCalledTimes(1)
expect(eventBusService.emit).toHaveBeenCalledWith(
"cart.updated",
expect.any(Object)
)
expect(cartRepository.findOne).toBeCalledTimes(1)
expect(cartRepository.findOne).toBeCalledWith(id)
expect(cartRepository.save).toBeCalledTimes(1)
expect(cartRepository.save).toBeCalledWith({
metadata: {},
})
})
it("works when metadata is empty", async () => {
const id = "empty"
await cartService.deleteMetadata(id, "existing")
expect(eventBusService.emit).toHaveBeenCalledTimes(1)
expect(eventBusService.emit).toHaveBeenCalledWith(
"cart.updated",
expect.any(Object)
)
expect(cartRepository.findOne).toBeCalledTimes(1)
expect(cartRepository.findOne).toBeCalledWith(id)
expect(cartRepository.save).toBeCalledTimes(1)
expect(cartRepository.save).toBeCalledWith({
metadata: {},
})
})
it("throw error on invalid key type", async () => {
try {
await cartService.deleteMetadata("testCart", 1234)
} catch (err) {
expect(err.message).toEqual(
"Key type is invalid. Metadata keys must be strings"
)
}
})
})
describe("create", () => { describe("create", () => {
const regionService = { const regionService = {
withTransaction: function () { withTransaction: function () {
@@ -1,16 +1,130 @@
import { IdMap, MockRepository, MockManager } from "medusa-test-utils" import { IdMap, MockRepository, MockManager } from "medusa-test-utils"
import SwapService from "../swap" import SwapService from "../swap"
import { InventoryServiceMock } from "../__mocks__/inventory" import { InventoryServiceMock } from "../__mocks__/inventory"
import { LineItemAdjustmentServiceMock } from "../__mocks__/line-item-adjustment" import { LineItemAdjustmentServiceMock } from "../__mocks__/line-item-adjustment"
import {
CustomShippingOptionService,
EventBusService,
FulfillmentService,
InventoryService,
LineItemService,
OrderService,
PaymentProviderService,
ReturnService,
ShippingOptionService,
TotalsService,
} from "../index"
import CartService from "../cart"
import { Order, ReturnItem, Swap } from "../../models"
import { SwapRepository } from "../../repositories/swap"
import LineItemAdjustmentService from "../line-item-adjustment"
/* ******************** DEFAULT REPOSITORY MOCKS ******************** */
const swapRepo = MockRepository({
findOneWithRelations: (existing) => Promise.resolve(existing),
create: jest.fn().mockImplementation((data) => {
return Object.assign(new Swap(), data)
}),
})
/* ******************** DEFAULT SERVICE MOCKS ******************** */
const eventBusService = { const eventBusService = {
emit: jest.fn(), emit: jest.fn(),
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} as unknown as EventBusService
const cartService = {
create: jest.fn().mockReturnValue(Promise.resolve({ id: "cart" })),
retrieve: jest
.fn()
.mockReturnValue(
Promise.resolve({ id: "cart", items: [{ id: "test-item" }] })
),
update: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function () {
return this
},
} as unknown as CartService
const customShippingOptionService = {
create: jest.fn().mockReturnValue(Promise.resolve({ id: "cso-test" })),
update: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function () {
return this
},
} as unknown as CustomShippingOptionService
const lineItemService = {
create: jest.fn().mockImplementation((d) => Promise.resolve(d)),
update: jest.fn().mockImplementation((d) => Promise.resolve(d)),
retrieve: () => Promise.resolve({}),
createReturnLines: jest.fn(() => Promise.resolve()),
withTransaction: function () {
return this
},
} as unknown as LineItemService
const totalsService = {
getTotal: () => {
return Promise.resolve(100)
},
} as unknown as TotalsService
const shippingOptionService = {
updateShippingMethod: () => {
return Promise.resolve()
},
withTransaction: function () {
return this
},
} as unknown as ShippingOptionService
const paymentProviderService = {
getStatus: jest.fn(() => {
return Promise.resolve("authorized")
}),
updatePayment: jest.fn(() => {
return Promise.resolve()
}),
cancelPayment: jest.fn(() => {
return Promise.resolve()
}),
withTransaction: function () {
return this
},
} as unknown as PaymentProviderService
const orderService = {} as unknown as OrderService
const returnService = {} as unknown as ReturnService
const inventoryService = {} as unknown as InventoryService
const fulfillmentService = {} as unknown as FulfillmentService
const lineItemAdjustmentService = {} as unknown as LineItemAdjustmentService
const defaultProps = {
manager: MockManager,
swapRepository: swapRepo,
cartService: cartService,
eventBus: eventBusService,
orderService: orderService,
returnService: returnService,
totalsService: totalsService,
eventBusService: eventBusService,
lineItemService: lineItemService,
inventoryService: inventoryService,
fulfillmentService: fulfillmentService,
shippingOptionService: shippingOptionService,
paymentProviderService: paymentProviderService,
lineItemAdjustmentService: lineItemAdjustmentService,
customShippingOptionService: customShippingOptionService,
} }
const generateOrder = (orderId, items, additional = {}) => { const generateOrder = (orderId, items, additional = {}): Order => {
return { return {
id: IdMap.getId(orderId), id: IdMap.getId(orderId),
items: items.map( items: items.map(
@@ -38,7 +152,7 @@ const generateOrder = (orderId, items, additional = {}) => {
}) })
), ),
...additional, ...additional,
} } as Order
} }
const testOrder = generateOrder( const testOrder = generateOrder(
@@ -74,70 +188,6 @@ const testOrder = generateOrder(
) )
describe("SwapService", () => { describe("SwapService", () => {
describe("validateReturnItems_", () => {
beforeEach(() => {
jest.clearAllMocks()
})
it("fails if item is returned", async () => {
const swapService = new SwapService({
eventBusService,
})
const res = () =>
swapService.validateReturnItems_(
{
items: [
{
id: IdMap.getId("line1"),
quantity: 1,
returned_quantity: 1,
},
],
},
[{ item_id: IdMap.getId("line1"), quantity: 1 }]
)
expect(res).toThrow("Cannot return more items than have been ordered")
})
it("fails if item is returned", async () => {
const swapService = new SwapService({})
const res = () =>
swapService.validateReturnItems_(
{
items: [
{
id: IdMap.getId("line1"),
quantity: 1,
returned_quantity: 1,
},
],
},
[{ item_id: IdMap.getId("line2"), quantity: 1 }]
)
expect(res).toThrow("Item does not exist on order")
})
it("successfully resolves", async () => {
const swapService = new SwapService({})
const res = swapService.validateReturnItems_(
{
items: [
{
id: IdMap.getId("line1"),
quantity: 1,
returned_quantity: 0,
},
],
},
[{ item_id: IdMap.getId("line1"), quantity: 1 }]
)
expect(res).toEqual([{ item_id: IdMap.getId("line1"), quantity: 1 }])
})
})
describe("createCart", () => { describe("createCart", () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks() jest.clearAllMocks()
@@ -166,10 +216,10 @@ describe("SwapService", () => {
Promise.resolve({ id: "cart", items: [{ id: "test-item" }] }) Promise.resolve({ id: "cart", items: [{ id: "test-item" }] })
), ),
update: jest.fn().mockReturnValue(Promise.resolve()), update: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as CartService
const swapRepo = MockRepository({ const swapRepo = MockRepository({
findOneWithRelations: () => Promise.resolve(existing), findOneWithRelations: () => Promise.resolve(existing),
@@ -178,29 +228,31 @@ describe("SwapService", () => {
const customShippingOptionService = { const customShippingOptionService = {
create: jest.fn().mockReturnValue(Promise.resolve({ id: "cso-test" })), create: jest.fn().mockReturnValue(Promise.resolve({ id: "cso-test" })),
update: jest.fn().mockReturnValue(Promise.resolve()), update: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as CustomShippingOptionService
const lineItemService = { const lineItemService = {
create: jest.fn().mockImplementation((d) => Promise.resolve(d)), create: jest.fn().mockImplementation((d) => Promise.resolve(d)),
update: jest.fn().mockImplementation((d) => Promise.resolve(d)), update: jest.fn().mockImplementation((d) => Promise.resolve(d)),
retrieve: () => Promise.resolve({}), retrieve: () => Promise.resolve({}),
createReturnLines: jest.fn(() => Promise.resolve()), createReturnLines: jest.fn(() => Promise.resolve()),
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as LineItemService
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
eventBusService, eventBusService,
swapRepository: swapRepo, swapRepository: swapRepo,
cartService, cartService,
lineItemService, lineItemService,
customShippingOptionService, customShippingOptionService,
lineItemAdjustmentService: LineItemAdjustmentServiceMock, lineItemAdjustmentService:
LineItemAdjustmentServiceMock as unknown as LineItemAdjustmentService,
}) })
it("finds swap and calls return create cart", async () => { it("finds swap and calls return create cart", async () => {
@@ -308,6 +360,7 @@ describe("SwapService", () => {
}) })
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
eventBusService, eventBusService,
swapRepository: swapRepo, swapRepository: swapRepo,
@@ -346,16 +399,20 @@ describe("SwapService", () => {
} }
}), }),
retrieve: () => Promise.resolve({}), retrieve: () => Promise.resolve({}),
} withTransaction: function () {
const swapRepo = MockRepository()
const returnService = {
create: jest.fn().mockReturnValue(Promise.resolve({ id: "ret" })),
withTransaction: function() {
return this return this
}, },
} } as unknown as LineItemService
const returnService = {
create: jest.fn().mockReturnValue(Promise.resolve({ id: "ret" })),
withTransaction: function () {
return this
},
} as unknown as ReturnService
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
eventBusService, eventBusService,
swapRepository: swapRepo, swapRepository: swapRepo,
@@ -369,7 +426,7 @@ describe("SwapService", () => {
[{ item_id: IdMap.getId("line"), quantity: 1 }], [{ item_id: IdMap.getId("line"), quantity: 1 }],
[{ variant_id: IdMap.getId("new-variant"), quantity: 1 }], [{ variant_id: IdMap.getId("new-variant"), quantity: 1 }],
{ {
id: IdMap.getId("return-shipping"), option_id: IdMap.getId("return-shipping"),
price: 20, price: 20,
} }
) )
@@ -388,7 +445,7 @@ describe("SwapService", () => {
[{ item_id: IdMap.getId("line"), quantity: 1 }], [{ item_id: IdMap.getId("line"), quantity: 1 }],
[{ variant_id: IdMap.getId("new-variant"), quantity: 1 }], [{ variant_id: IdMap.getId("new-variant"), quantity: 1 }],
{ {
id: IdMap.getId("return-shipping"), option_id: IdMap.getId("return-shipping"),
price: 20, price: 20,
} }
) )
@@ -422,7 +479,7 @@ describe("SwapService", () => {
[{ item_id: IdMap.getId("line"), quantity: 1 }], [{ item_id: IdMap.getId("line"), quantity: 1 }],
[{ variant_id: IdMap.getId("new-variant"), quantity: 1 }], [{ variant_id: IdMap.getId("new-variant"), quantity: 1 }],
{ {
id: IdMap.getId("return-shipping"), option_id: IdMap.getId("return-shipping"),
price: 20, price: 20,
}, },
{ no_notification: input } { no_notification: input }
@@ -451,10 +508,10 @@ describe("SwapService", () => {
{ items: [{ item_id: "1234", quantity: 2 }], data: "new" }, { items: [{ item_id: "1234", quantity: 2 }], data: "new" },
]) ])
), ),
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as FulfillmentService
const existing = { const existing = {
fulfillment_status: "not_fulfilled", fulfillment_status: "not_fulfilled",
@@ -472,15 +529,16 @@ describe("SwapService", () => {
const lineItemService = { const lineItemService = {
update: jest.fn(), update: jest.fn(),
retrieve: () => Promise.resolve({}), retrieve: () => Promise.resolve({}),
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as LineItemService
const swapRepo = MockRepository({ const swapRepo = MockRepository({
findOneWithRelations: () => Promise.resolve({ ...existing }), findOneWithRelations: () => Promise.resolve({ ...existing }),
}) })
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
eventBusService, eventBusService,
swapRepository: swapRepo, swapRepository: swapRepo,
@@ -531,7 +589,9 @@ describe("SwapService", () => {
canceled_at: new Date(), canceled_at: new Date(),
}), }),
}) })
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
swapRepository: swapRepo, swapRepository: swapRepo,
}) })
@@ -561,12 +621,13 @@ describe("SwapService", () => {
}) })
} }
}), }),
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as FulfillmentService
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
swapRepository: swapRepo, swapRepository: swapRepo,
fulfillmentService, fulfillmentService,
@@ -615,17 +676,10 @@ describe("SwapService", () => {
data: "new", data: "new",
}) })
}), }),
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as FulfillmentService
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
return this
},
}
const existing = { const existing = {
fulfillment_status: "not_fulfilled", fulfillment_status: "not_fulfilled",
@@ -660,14 +714,6 @@ describe("SwapService", () => {
other: "data", other: "data",
} }
const lineItemService = {
update: jest.fn(),
retrieve: () => Promise.resolve({}),
withTransaction: function() {
return this
},
}
const cartService = { const cartService = {
update: jest.fn(), update: jest.fn(),
retrieve: jest retrieve: jest
@@ -675,16 +721,17 @@ describe("SwapService", () => {
.mockReturnValue( .mockReturnValue(
Promise.resolve({ id: "cart", items: [{ id: "test-item" }] }) Promise.resolve({ id: "cart", items: [{ id: "test-item" }] })
), ),
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as CartService
const swapRepo = MockRepository({ const swapRepo = MockRepository({
findOneWithRelations: () => Promise.resolve(existing), findOneWithRelations: () => Promise.resolve(existing),
}) })
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
eventBusService, eventBusService,
swapRepository: swapRepo, swapRepository: swapRepo,
@@ -697,7 +744,7 @@ describe("SwapService", () => {
await swapService.createShipment( await swapService.createShipment(
IdMap.getId("swap"), IdMap.getId("swap"),
IdMap.getId("f1"), IdMap.getId("f1"),
["1234"], [{ tracking_number: "1234" }],
{} {}
) )
@@ -715,7 +762,7 @@ describe("SwapService", () => {
expect(fulfillmentService.createShipment).toHaveBeenCalledWith( expect(fulfillmentService.createShipment).toHaveBeenCalledWith(
IdMap.getId("f1"), IdMap.getId("f1"),
["1234"], [{ tracking_number: "1234" }],
{} {}
) )
}) })
@@ -728,6 +775,7 @@ describe("SwapService", () => {
}) })
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
swapRepository: swapRepo, swapRepository: swapRepo,
}) })
@@ -735,7 +783,8 @@ describe("SwapService", () => {
it("fails when swap is canceled", async () => { it("fails when swap is canceled", async () => {
await expect( await expect(
swapService.createShipment( swapService.createShipment(
IdMap.getId("swap", IdMap.getId("fulfillment"), [], {}) IdMap.getId("swap"),
IdMap.getId("fulfillment")
) )
).rejects.toThrow("Canceled swap cannot be fulfilled as shipped") ).rejects.toThrow("Canceled swap cannot be fulfilled as shipped")
}) })
@@ -748,27 +797,20 @@ describe("SwapService", () => {
Date.now = jest.fn(() => 1572393600000) Date.now = jest.fn(() => 1572393600000)
}) })
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
return this
},
}
const totalsService = { const totalsService = {
getTotal: () => { getTotal: () => {
return Promise.resolve(100) return Promise.resolve(100)
}, },
} } as unknown as TotalsService
const shippingOptionService = { const shippingOptionService = {
updateShippingMethod: () => { updateShippingMethod: () => {
return Promise.resolve() return Promise.resolve()
}, },
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as ShippingOptionService
const cartService = { const cartService = {
retrieve: jest.fn().mockReturnValue( retrieve: jest.fn().mockReturnValue(
@@ -780,10 +822,10 @@ describe("SwapService", () => {
update: () => { update: () => {
return Promise.resolve() return Promise.resolve()
}, },
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as CartService
const paymentProviderService = { const paymentProviderService = {
getStatus: jest.fn(() => { getStatus: jest.fn(() => {
@@ -795,17 +837,17 @@ describe("SwapService", () => {
cancelPayment: jest.fn(() => { cancelPayment: jest.fn(() => {
return Promise.resolve() return Promise.resolve()
}), }),
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as PaymentProviderService
const inventoryService = { const inventoryService = {
...InventoryServiceMock, ...InventoryServiceMock,
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as InventoryService
describe("success", () => { describe("success", () => {
const cart = { const cart = {
@@ -821,13 +863,14 @@ describe("SwapService", () => {
other: "data", other: "data",
} }
cartService.retrieve = () => cart cartService.retrieve = (() => cart) as unknown as CartService["retrieve"]
const swapRepo = MockRepository({ const swapRepo = MockRepository({
findOneWithRelations: () => Promise.resolve(existing), findOneWithRelations: () => Promise.resolve(existing),
}) })
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
eventBusService, eventBusService,
swapRepository: swapRepo, swapRepository: swapRepo,
@@ -885,11 +928,11 @@ describe("SwapService", () => {
return Promise.resolve(existing) return Promise.resolve(existing)
} }
}, },
}) }) as unknown as typeof SwapRepository
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
swapRepo: swapRepo,
eventBusService, eventBusService,
swapRepository: swapRepo, swapRepository: swapRepo,
totalsService, totalsService,
@@ -922,13 +965,6 @@ describe("SwapService", () => {
}) })
describe("success", () => { describe("success", () => {
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
return this
},
}
const paymentProviderService = { const paymentProviderService = {
capturePayment: jest.fn((g) => capturePayment: jest.fn((g) =>
g.id === "good" ? Promise.resolve() : Promise.reject() g.id === "good" ? Promise.resolve() : Promise.reject()
@@ -936,10 +972,10 @@ describe("SwapService", () => {
refundPayment: jest.fn((g) => refundPayment: jest.fn((g) =>
g[0].id === "good" ? Promise.resolve() : Promise.reject() g[0].id === "good" ? Promise.resolve() : Promise.reject()
), ),
withTransaction: function() { withTransaction: function () {
return this return this
}, },
} } as unknown as PaymentProviderService
const existing = (dif, fail, conf = true) => ({ const existing = (dif, fail, conf = true) => ({
confirmed_at: conf ? "1234" : null, confirmed_at: conf ? "1234" : null,
@@ -969,9 +1005,16 @@ describe("SwapService", () => {
return Promise.resolve(existing(1, false)) return Promise.resolve(existing(1, false))
} }
}, },
create: jest.fn().mockImplementation((data) => {
return Object.assign(new Swap(), data)
}),
save: jest.fn().mockImplementation((data) => {
return Object.assign(new Swap(), data)
}),
}) })
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
swapRepository: swapRepo, swapRepository: swapRepo,
paymentProviderService, paymentProviderService,
@@ -983,6 +1026,7 @@ describe("SwapService", () => {
expect(paymentProviderService.capturePayment).toHaveBeenCalledWith({ expect(paymentProviderService.capturePayment).toHaveBeenCalledWith({
id: "good", id: "good",
}) })
expect(swapRepo.save).toHaveBeenCalledWith({ expect(swapRepo.save).toHaveBeenCalledWith({
...existing(1, false), ...existing(1, false),
payment_status: "captured", payment_status: "captured",
@@ -994,6 +1038,7 @@ describe("SwapService", () => {
expect(paymentProviderService.capturePayment).toHaveBeenCalledWith({ expect(paymentProviderService.capturePayment).toHaveBeenCalledWith({
id: "f", id: "f",
}) })
expect(swapRepo.save).toHaveBeenCalledWith({ expect(swapRepo.save).toHaveBeenCalledWith({
...existing(1, true), ...existing(1, true),
payment_status: "requires_action", payment_status: "requires_action",
@@ -1011,6 +1056,7 @@ describe("SwapService", () => {
1, 1,
"swap" "swap"
) )
expect(swapRepo.save).toHaveBeenCalledWith({ expect(swapRepo.save).toHaveBeenCalledWith({
...existing(-1, false), ...existing(-1, false),
payment_status: "difference_refunded", payment_status: "difference_refunded",
@@ -1029,6 +1075,7 @@ describe("SwapService", () => {
1, 1,
"swap" "swap"
) )
expect(swapRepo.save).toHaveBeenCalledWith({ expect(swapRepo.save).toHaveBeenCalledWith({
...existing(-1, true), ...existing(-1, true),
payment_status: "requires_action", payment_status: "requires_action",
@@ -1061,13 +1108,6 @@ describe("SwapService", () => {
jest.clearAllMocks() jest.clearAllMocks()
}) })
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
return this
},
}
const swapRepo = MockRepository({ const swapRepo = MockRepository({
findOneWithRelations: (rels, q) => { findOneWithRelations: (rels, q) => {
switch (q.where.id) { switch (q.where.id) {
@@ -1094,6 +1134,7 @@ describe("SwapService", () => {
}) })
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
swapRepository: swapRepo, swapRepository: swapRepo,
eventBusService, eventBusService,
@@ -1124,20 +1165,14 @@ describe("SwapService", () => {
const return_order = { status: "canceled" } const return_order = { status: "canceled" }
const fulfillment = { canceled_at: now } const fulfillment = { canceled_at: now }
const paymentProviderService = {
cancelPayment: jest.fn(() => Promise.resolve({})),
withTransaction: function() {
return this
},
}
const swapRepo = MockRepository({ const swapRepo = MockRepository({
findOneWithRelations: (_, q) => { findOneWithRelations: (_, q) => {
const swap = { const swap: any = {
payment: { ...payment }, payment: { ...payment },
return_order: { ...return_order }, return_order: { ...return_order },
fulfillments: [{ ...fulfillment }, { ...fulfillment }], fulfillments: [{ ...fulfillment }, { ...fulfillment }],
} }
switch (q.where.id) { switch (q.where.id) {
case IdMap.getId("fail-fulfillment"): case IdMap.getId("fail-fulfillment"):
swap.fulfillments[1].canceled_at = undefined swap.fulfillments[1].canceled_at = undefined
@@ -1162,6 +1197,7 @@ describe("SwapService", () => {
}) })
const swapService = new SwapService({ const swapService = new SwapService({
...defaultProps,
manager: MockManager, manager: MockManager,
swapRepository: swapRepo, swapRepository: swapRepo,
paymentProviderService, paymentProviderService,
-42
View File
@@ -2145,48 +2145,6 @@ class CartService extends TransactionBaseService {
.withTransaction(transactionManager) .withTransaction(transactionManager)
.createAdjustments(cart) .createAdjustments(cart)
} }
/**
* Dedicated method to delete metadata for a cart.
* @param cartId - the cart to delete metadata from.
* @param key - key for metadata field
* @return resolves to the updated result.
*/
async deleteMetadata(cartId: string, key: string): Promise<Cart> {
return await this.atomicPhase_(
async (transactionManager: EntityManager) => {
const cartRepo = transactionManager.getCustomRepository(
this.cartRepository_
)
const validatedId = validateId(cartId)
if (typeof key !== "string") {
throw new MedusaError(
MedusaError.Types.INVALID_ARGUMENT,
"Key type is invalid. Metadata keys must be strings"
)
}
const cart = await cartRepo.findOne(validatedId)
if (!cart) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`Cart with id: ${validatedId} was not found`
)
}
const updated = cart.metadata || {}
delete updated[key]
cart.metadata = updated
const updatedCart = await cartRepo.save(cart)
this.eventBus_
.withTransaction(transactionManager)
.emit(CartService.Events.UPDATED, updatedCart)
return updatedCart
}
)
}
} }
export default CartService export default CartService
+15
View File
@@ -1,6 +1,7 @@
import { MedusaError } from "medusa-core-utils" import { MedusaError } from "medusa-core-utils"
import { BaseService } from "medusa-interfaces" import { BaseService } from "medusa-interfaces"
import { EntityManager } from "typeorm" import { EntityManager } from "typeorm"
import { DeepPartial } from "typeorm/common/DeepPartial"
import { LineItemRepository } from "../repositories/line-item" import { LineItemRepository } from "../repositories/line-item"
import { LineItemTaxLineRepository } from "../repositories/line-item-tax-line" import { LineItemTaxLineRepository } from "../repositories/line-item-tax-line"
import { import {
@@ -15,6 +16,7 @@ import LineItemAdjustmentService from "./line-item-adjustment"
import { Cart } from "../models/cart" import { Cart } from "../models/cart"
import { LineItemAdjustment } from "../models/line-item-adjustment" import { LineItemAdjustment } from "../models/line-item-adjustment"
import { FindConfig } from "../types/common" import { FindConfig } from "../types/common"
import { LineItemTaxLine } from "../models"
type InjectedDependencies = { type InjectedDependencies = {
manager: EntityManager manager: EntityManager
@@ -325,6 +327,19 @@ class LineItemService extends BaseService {
} }
) )
} }
/**
* Create a line item tax line.
* @param args - tax line partial passed to the repo create method
* @return a new line item tax line
*/
public createTaxLine(args: DeepPartial<LineItemTaxLine>): LineItemTaxLine {
const itemTaxLineRepo = this.manager_.getCustomRepository(
this.itemTaxLineRepo_
)
return itemTaxLineRepo.create(args)
}
} }
export default LineItemService export default LineItemService
File diff suppressed because it is too large. Load diff
+4 -2
View File
@@ -3,8 +3,8 @@ import {
ClaimOrder, ClaimOrder,
Discount, Discount,
LineItem, LineItem,
Order,
Payment, Payment,
Region,
ShippingMethod, ShippingMethod,
} from "../models" } from "../models"
@@ -19,7 +19,7 @@ export type FulfillmentItemPartition = {
} }
export type CreateShipmentConfig = { export type CreateShipmentConfig = {
metadata: Record<string, unknown> metadata?: Record<string, unknown>
no_notification?: boolean no_notification?: boolean
} }
@@ -31,6 +31,8 @@ export type CreateFulfillmentOrder = Omit<ClaimOrder, "beforeInsert"> & {
currency_code: string currency_code: string
tax_rate: number | null tax_rate: number | null
region_id: string region_id: string
region?: Region
is_swap?: boolean
display_id: number display_id: number
billing_address: Address billing_address: Address
items: LineItem[] items: LineItem[]