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ć
2022-09-05 15:37:47 +02:00
committed by GitHub
parent 546a963f7b
commit ba6416f095
14 changed files with 609 additions and 599 deletions

View File

@@ -36,7 +36,7 @@ import { validator } from "../../../../utils/validator"
* items:
* type: string
* 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
* tags:
* - Swap

View File

@@ -67,7 +67,7 @@ export default async (req, res) => {
export class AdminPostOrdersOrderSwapsSwapFulfillmentsReq {
@IsObject()
@IsOptional()
metadata?: object
metadata?: Record<string, unknown>
@IsBoolean()
@IsOptional()

View File

@@ -1,8 +1,10 @@
import { Type } from "class-transformer"
import { IsInt, IsOptional } from "class-validator"
import { SwapService } from "../../../../services"
import { Type } from "class-transformer"
import { validator } from "../../../../utils/validator"
import { FindConfig } from "../../../../types/common"
import { Swap } from "../../../../models"
/**
* @oas [get] /swaps
@@ -43,7 +45,7 @@ export default async (req, res) => {
const selector = {}
const listConfig = {
const listConfig: FindConfig<Swap> = {
skip: offset,
take: limit,
order: { created_at: "DESC" },

View File

@@ -1,6 +1,8 @@
import { Swap } from "./../../../../"
import { Router } from "express"
import { Swap } from "./../../../../"
import middlewares from "../../../middlewares"
import { FindConfig } from "../../../../types/common"
const route = Router()
@@ -27,7 +29,7 @@ export const defaultStoreSwapRelations = [
"shipping_methods",
"cart",
]
export const defaultStoreSwapFields = [
export const defaultStoreSwapFields: FindConfig<Swap>["select"] = [
"id",
"fulfillment_status",
"payment_status",

View File

@@ -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"`
)
}
}

View File

@@ -25,6 +25,7 @@ export enum SwapFulfillmentStatus {
NOT_FULFILLED = "not_fulfilled",
FULFILLED = "fulfilled",
SHIPPED = "shipped",
PARTIALLY_SHIPPED = "partially_shipped",
CANCELED = "canceled",
REQUIRES_ACTION = "requires_action",
}
@@ -190,7 +191,7 @@ export class Swap extends SoftDeletableEntity {
* description: Available if the relation `shipping_address` is expanded.
* $ref: "#/components/schemas/address"
* 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
* items:
* $ref: "#/components/schemas/shipping_method"

View File

@@ -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", () => {
const regionService = {
withTransaction: function () {

View File

@@ -1,16 +1,130 @@
import { IdMap, MockRepository, MockManager } from "medusa-test-utils"
import SwapService from "../swap"
import { InventoryServiceMock } from "../__mocks__/inventory"
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 = {
emit: jest.fn(),
withTransaction: function() {
withTransaction: function () {
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 {
id: IdMap.getId(orderId),
items: items.map(
@@ -38,7 +152,7 @@ const generateOrder = (orderId, items, additional = {}) => {
})
),
...additional,
}
} as Order
}
const testOrder = generateOrder(
@@ -74,70 +188,6 @@ const testOrder = generateOrder(
)
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", () => {
beforeEach(() => {
jest.clearAllMocks()
@@ -166,10 +216,10 @@ describe("SwapService", () => {
Promise.resolve({ id: "cart", items: [{ id: "test-item" }] })
),
update: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
withTransaction: function () {
return this
},
}
} as unknown as CartService
const swapRepo = MockRepository({
findOneWithRelations: () => Promise.resolve(existing),
@@ -178,29 +228,31 @@ describe("SwapService", () => {
const customShippingOptionService = {
create: jest.fn().mockReturnValue(Promise.resolve({ id: "cso-test" })),
update: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
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() {
withTransaction: function () {
return this
},
}
} as unknown as LineItemService
const swapService = new SwapService({
...defaultProps,
manager: MockManager,
eventBusService,
swapRepository: swapRepo,
cartService,
lineItemService,
customShippingOptionService,
lineItemAdjustmentService: LineItemAdjustmentServiceMock,
lineItemAdjustmentService:
LineItemAdjustmentServiceMock as unknown as LineItemAdjustmentService,
})
it("finds swap and calls return create cart", async () => {
@@ -308,6 +360,7 @@ describe("SwapService", () => {
})
const swapService = new SwapService({
...defaultProps,
manager: MockManager,
eventBusService,
swapRepository: swapRepo,
@@ -346,16 +399,20 @@ describe("SwapService", () => {
}
}),
retrieve: () => Promise.resolve({}),
}
const swapRepo = MockRepository()
const returnService = {
create: jest.fn().mockReturnValue(Promise.resolve({ id: "ret" })),
withTransaction: function() {
withTransaction: function () {
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({
...defaultProps,
manager: MockManager,
eventBusService,
swapRepository: swapRepo,
@@ -369,7 +426,7 @@ describe("SwapService", () => {
[{ item_id: IdMap.getId("line"), quantity: 1 }],
[{ variant_id: IdMap.getId("new-variant"), quantity: 1 }],
{
id: IdMap.getId("return-shipping"),
option_id: IdMap.getId("return-shipping"),
price: 20,
}
)
@@ -388,7 +445,7 @@ describe("SwapService", () => {
[{ item_id: IdMap.getId("line"), quantity: 1 }],
[{ variant_id: IdMap.getId("new-variant"), quantity: 1 }],
{
id: IdMap.getId("return-shipping"),
option_id: IdMap.getId("return-shipping"),
price: 20,
}
)
@@ -422,7 +479,7 @@ describe("SwapService", () => {
[{ item_id: IdMap.getId("line"), quantity: 1 }],
[{ variant_id: IdMap.getId("new-variant"), quantity: 1 }],
{
id: IdMap.getId("return-shipping"),
option_id: IdMap.getId("return-shipping"),
price: 20,
},
{ no_notification: input }
@@ -451,10 +508,10 @@ describe("SwapService", () => {
{ items: [{ item_id: "1234", quantity: 2 }], data: "new" },
])
),
withTransaction: function() {
withTransaction: function () {
return this
},
}
} as unknown as FulfillmentService
const existing = {
fulfillment_status: "not_fulfilled",
@@ -472,15 +529,16 @@ describe("SwapService", () => {
const lineItemService = {
update: jest.fn(),
retrieve: () => Promise.resolve({}),
withTransaction: function() {
withTransaction: function () {
return this
},
}
} as unknown as LineItemService
const swapRepo = MockRepository({
findOneWithRelations: () => Promise.resolve({ ...existing }),
})
const swapService = new SwapService({
...defaultProps,
manager: MockManager,
eventBusService,
swapRepository: swapRepo,
@@ -531,7 +589,9 @@ describe("SwapService", () => {
canceled_at: new Date(),
}),
})
const swapService = new SwapService({
...defaultProps,
manager: MockManager,
swapRepository: swapRepo,
})
@@ -561,12 +621,13 @@ describe("SwapService", () => {
})
}
}),
withTransaction: function() {
withTransaction: function () {
return this
},
}
} as unknown as FulfillmentService
const swapService = new SwapService({
...defaultProps,
manager: MockManager,
swapRepository: swapRepo,
fulfillmentService,
@@ -615,17 +676,10 @@ describe("SwapService", () => {
data: "new",
})
}),
withTransaction: function() {
withTransaction: function () {
return this
},
}
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
return this
},
}
} as unknown as FulfillmentService
const existing = {
fulfillment_status: "not_fulfilled",
@@ -660,14 +714,6 @@ describe("SwapService", () => {
other: "data",
}
const lineItemService = {
update: jest.fn(),
retrieve: () => Promise.resolve({}),
withTransaction: function() {
return this
},
}
const cartService = {
update: jest.fn(),
retrieve: jest
@@ -675,16 +721,17 @@ describe("SwapService", () => {
.mockReturnValue(
Promise.resolve({ id: "cart", items: [{ id: "test-item" }] })
),
withTransaction: function() {
withTransaction: function () {
return this
},
}
} as unknown as CartService
const swapRepo = MockRepository({
findOneWithRelations: () => Promise.resolve(existing),
})
const swapService = new SwapService({
...defaultProps,
manager: MockManager,
eventBusService,
swapRepository: swapRepo,
@@ -697,7 +744,7 @@ describe("SwapService", () => {
await swapService.createShipment(
IdMap.getId("swap"),
IdMap.getId("f1"),
["1234"],
[{ tracking_number: "1234" }],
{}
)
@@ -715,7 +762,7 @@ describe("SwapService", () => {
expect(fulfillmentService.createShipment).toHaveBeenCalledWith(
IdMap.getId("f1"),
["1234"],
[{ tracking_number: "1234" }],
{}
)
})
@@ -728,6 +775,7 @@ describe("SwapService", () => {
})
const swapService = new SwapService({
...defaultProps,
manager: MockManager,
swapRepository: swapRepo,
})
@@ -735,7 +783,8 @@ describe("SwapService", () => {
it("fails when swap is canceled", async () => {
await expect(
swapService.createShipment(
IdMap.getId("swap", IdMap.getId("fulfillment"), [], {})
IdMap.getId("swap"),
IdMap.getId("fulfillment")
)
).rejects.toThrow("Canceled swap cannot be fulfilled as shipped")
})
@@ -748,27 +797,20 @@ describe("SwapService", () => {
Date.now = jest.fn(() => 1572393600000)
})
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
return this
},
}
const totalsService = {
getTotal: () => {
return Promise.resolve(100)
},
}
} as unknown as TotalsService
const shippingOptionService = {
updateShippingMethod: () => {
return Promise.resolve()
},
withTransaction: function() {
withTransaction: function () {
return this
},
}
} as unknown as ShippingOptionService
const cartService = {
retrieve: jest.fn().mockReturnValue(
@@ -780,10 +822,10 @@ describe("SwapService", () => {
update: () => {
return Promise.resolve()
},
withTransaction: function() {
withTransaction: function () {
return this
},
}
} as unknown as CartService
const paymentProviderService = {
getStatus: jest.fn(() => {
@@ -795,17 +837,17 @@ describe("SwapService", () => {
cancelPayment: jest.fn(() => {
return Promise.resolve()
}),
withTransaction: function() {
withTransaction: function () {
return this
},
}
} as unknown as PaymentProviderService
const inventoryService = {
...InventoryServiceMock,
withTransaction: function() {
withTransaction: function () {
return this
},
}
} as unknown as InventoryService
describe("success", () => {
const cart = {
@@ -821,13 +863,14 @@ describe("SwapService", () => {
other: "data",
}
cartService.retrieve = () => cart
cartService.retrieve = (() => cart) as unknown as CartService["retrieve"]
const swapRepo = MockRepository({
findOneWithRelations: () => Promise.resolve(existing),
})
const swapService = new SwapService({
...defaultProps,
manager: MockManager,
eventBusService,
swapRepository: swapRepo,
@@ -885,11 +928,11 @@ describe("SwapService", () => {
return Promise.resolve(existing)
}
},
})
}) as unknown as typeof SwapRepository
const swapService = new SwapService({
...defaultProps,
manager: MockManager,
swapRepo: swapRepo,
eventBusService,
swapRepository: swapRepo,
totalsService,
@@ -922,13 +965,6 @@ describe("SwapService", () => {
})
describe("success", () => {
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
return this
},
}
const paymentProviderService = {
capturePayment: jest.fn((g) =>
g.id === "good" ? Promise.resolve() : Promise.reject()
@@ -936,10 +972,10 @@ describe("SwapService", () => {
refundPayment: jest.fn((g) =>
g[0].id === "good" ? Promise.resolve() : Promise.reject()
),
withTransaction: function() {
withTransaction: function () {
return this
},
}
} as unknown as PaymentProviderService
const existing = (dif, fail, conf = true) => ({
confirmed_at: conf ? "1234" : null,
@@ -969,9 +1005,16 @@ describe("SwapService", () => {
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({
...defaultProps,
manager: MockManager,
swapRepository: swapRepo,
paymentProviderService,
@@ -983,6 +1026,7 @@ describe("SwapService", () => {
expect(paymentProviderService.capturePayment).toHaveBeenCalledWith({
id: "good",
})
expect(swapRepo.save).toHaveBeenCalledWith({
...existing(1, false),
payment_status: "captured",
@@ -994,6 +1038,7 @@ describe("SwapService", () => {
expect(paymentProviderService.capturePayment).toHaveBeenCalledWith({
id: "f",
})
expect(swapRepo.save).toHaveBeenCalledWith({
...existing(1, true),
payment_status: "requires_action",
@@ -1011,6 +1056,7 @@ describe("SwapService", () => {
1,
"swap"
)
expect(swapRepo.save).toHaveBeenCalledWith({
...existing(-1, false),
payment_status: "difference_refunded",
@@ -1029,6 +1075,7 @@ describe("SwapService", () => {
1,
"swap"
)
expect(swapRepo.save).toHaveBeenCalledWith({
...existing(-1, true),
payment_status: "requires_action",
@@ -1061,13 +1108,6 @@ describe("SwapService", () => {
jest.clearAllMocks()
})
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
return this
},
}
const swapRepo = MockRepository({
findOneWithRelations: (rels, q) => {
switch (q.where.id) {
@@ -1094,6 +1134,7 @@ describe("SwapService", () => {
})
const swapService = new SwapService({
...defaultProps,
manager: MockManager,
swapRepository: swapRepo,
eventBusService,
@@ -1124,20 +1165,14 @@ describe("SwapService", () => {
const return_order = { status: "canceled" }
const fulfillment = { canceled_at: now }
const paymentProviderService = {
cancelPayment: jest.fn(() => Promise.resolve({})),
withTransaction: function() {
return this
},
}
const swapRepo = MockRepository({
findOneWithRelations: (_, q) => {
const swap = {
const swap: any = {
payment: { ...payment },
return_order: { ...return_order },
fulfillments: [{ ...fulfillment }, { ...fulfillment }],
}
switch (q.where.id) {
case IdMap.getId("fail-fulfillment"):
swap.fulfillments[1].canceled_at = undefined
@@ -1162,6 +1197,7 @@ describe("SwapService", () => {
})
const swapService = new SwapService({
...defaultProps,
manager: MockManager,
swapRepository: swapRepo,
paymentProviderService,

View File

@@ -2145,48 +2145,6 @@ class CartService extends TransactionBaseService {
.withTransaction(transactionManager)
.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

View File

@@ -1,6 +1,7 @@
import { MedusaError } from "medusa-core-utils"
import { BaseService } from "medusa-interfaces"
import { EntityManager } from "typeorm"
import { DeepPartial } from "typeorm/common/DeepPartial"
import { LineItemRepository } from "../repositories/line-item"
import { LineItemTaxLineRepository } from "../repositories/line-item-tax-line"
import {
@@ -15,6 +16,7 @@ import LineItemAdjustmentService from "./line-item-adjustment"
import { Cart } from "../models/cart"
import { LineItemAdjustment } from "../models/line-item-adjustment"
import { FindConfig } from "../types/common"
import { LineItemTaxLine } from "../models"
type InjectedDependencies = {
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

View File

@@ -3,8 +3,8 @@ import {
ClaimOrder,
Discount,
LineItem,
Order,
Payment,
Region,
ShippingMethod,
} from "../models"
@@ -19,7 +19,7 @@ export type FulfillmentItemPartition = {
}
export type CreateShipmentConfig = {
metadata: Record<string, unknown>
metadata?: Record<string, unknown>
no_notification?: boolean
}
@@ -31,6 +31,8 @@ export type CreateFulfillmentOrder = Omit<ClaimOrder, "beforeInsert"> & {
currency_code: string
tax_rate: number | null
region_id: string
region?: Region
is_swap?: boolean
display_id: number
billing_address: Address
items: LineItem[]