diff --git a/integration-tests/api/helpers/swap-seeder.js b/integration-tests/api/helpers/swap-seeder.js index 8960fc9d3b..7a93c0f1ce 100644 --- a/integration-tests/api/helpers/swap-seeder.js +++ b/integration-tests/api/helpers/swap-seeder.js @@ -11,10 +11,18 @@ const { const { CustomShippingOption, } = require("@medusajs/medusa/dist/models/custom-shipping-option") +const { Region } = require("@medusajs/medusa/dist/models/region") + +let regionId +let region module.exports = async (connection, data = {}) => { const manager = connection.manager + regionId = "test-region" + + region = await manager.findOne(Region, { id: regionId }) + let orderWithSwap = manager.create(Order, { id: "order-with-swap", customer_id: "test-customer", @@ -30,7 +38,7 @@ module.exports = async (connection, data = {}) => { first_name: "lebron", country_code: "us", }, - region_id: "test-region", + region_id: regionId, currency_code: "usd", tax_rate: 0, discounts: [], @@ -56,7 +64,7 @@ module.exports = async (connection, data = {}) => { email: "test-customer@email.com", shipping_address_id: "test-shipping-address", billing_address_id: "test-billing-address", - region_id: "test-region", + region_id: regionId, type: "swap", metadata: { swap_id: "test-swap", @@ -103,7 +111,7 @@ module.exports = async (connection, data = {}) => { email: "test-customer@email.com", shipping_address_id: "test-shipping-address", billing_address_id: "test-billing-address", - region_id: "test-region", + region_id: regionId, type: "swap", metadata: { swap_id: "test-swap", @@ -170,7 +178,7 @@ module.exports = async (connection, data = {}) => { email: "test-customer@email.com", shipping_address_id: "test-shipping-address", billing_address_id: "test-billing-address", - region_id: "test-region", + region_id: regionId, type: "swap", metadata: {}, ...data, @@ -349,7 +357,7 @@ const createSwap = async (options, manager) => { is_disabled: false, rule: dRule, }) - let discountDb = await manager.save(discount) + const discountDb = await manager.save(discount) const cart = manager.create(Cart, { id: `${swapId}-cart`, @@ -357,7 +365,7 @@ const createSwap = async (options, manager) => { email: "test-customer@email.com", shipping_address_id: "test-shipping-address", billing_address_id: "test-billing-address", - region_id: "test-region", + region_id: regionId, type: "swap", discounts: [discount], metadata: { @@ -396,6 +404,13 @@ const createSwap = async (options, manager) => { thumbnail: "https://test.js/1234", unit_price: 8000, quantity: 1, + tax_lines: [ + { + rate: region.tax_rate, + code: region.name, + name: region.name, + }, + ], adjustments: [ { amount: -800, diff --git a/packages/medusa/src/api/routes/admin/orders/create-swap.ts b/packages/medusa/src/api/routes/admin/orders/create-swap.ts index 29a231f7c1..25ade65707 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-swap.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-swap.ts @@ -138,9 +138,9 @@ export default async (req, res) => { .workStage(idempotencyKey.idempotency_key, async (manager) => { const order = await orderService .withTransaction(manager) - .retrieve(id, { - select: ["refunded_total", "total"], + .retrieveWithTotals(id, { relations: [ + "cart", "items", "items.tax_lines", "swaps", diff --git a/packages/medusa/src/services/__tests__/swap.ts b/packages/medusa/src/services/__tests__/swap.ts index 3cfab43ad8..cd10da6139 100644 --- a/packages/medusa/src/services/__tests__/swap.ts +++ b/packages/medusa/src/services/__tests__/swap.ts @@ -1,7 +1,11 @@ import { IdMap, MockManager, MockRepository } from "medusa-test-utils" import SwapService from "../swap" -import { ProductVariantInventoryServiceMock } from "../__mocks__/product-variant-inventory" -import { LineItemAdjustmentServiceMock } from "../__mocks__/line-item-adjustment" +import { + ProductVariantInventoryServiceMock +} from "../__mocks__/product-variant-inventory" +import { + LineItemAdjustmentServiceMock +} from "../__mocks__/line-item-adjustment" import { CustomShippingOptionService, EventBusService, @@ -65,6 +69,7 @@ const lineItemService = { create: jest.fn().mockImplementation((d) => Promise.resolve(d)), update: jest.fn().mockImplementation((d) => Promise.resolve(d)), retrieve: () => Promise.resolve({}), + list: () => Promise.resolve([]), createReturnLines: jest.fn(() => Promise.resolve()), withTransaction: function () { return this @@ -240,6 +245,7 @@ describe("SwapService", () => { create: jest.fn().mockImplementation((d) => Promise.resolve(d)), update: jest.fn().mockImplementation((d) => Promise.resolve(d)), retrieve: () => Promise.resolve({}), + list: () => Promise.resolve([]), createReturnLines: jest.fn(() => Promise.resolve()), withTransaction: function () { return this @@ -400,7 +406,7 @@ describe("SwapService", () => { const lineItemService = { generate: jest .fn() - .mockImplementation((variantId, regionId, quantity) => { + .mockImplementation(({ variantId, quantity }) => { return { unit_price: 100, variant_id: variantId, @@ -408,6 +414,7 @@ describe("SwapService", () => { } }), retrieve: () => Promise.resolve({}), + list: () => Promise.resolve([]), withTransaction: function () { return this }, @@ -441,11 +448,13 @@ describe("SwapService", () => { ) expect(lineItemService.generate).toHaveBeenCalledTimes(1) - expect(lineItemService.generate).toHaveBeenCalledWith( - IdMap.getId("new-variant"), - IdMap.getId("region"), - 1 - ) + expect(lineItemService.generate).toHaveBeenCalledWith({ + quantity: 1, + variantId: IdMap.getId("new-variant") + }, { + "cart": undefined, + region_id: IdMap.getId("region") + }) }) it("creates swap", async () => { @@ -538,6 +547,7 @@ describe("SwapService", () => { const lineItemService = { update: jest.fn(), retrieve: () => Promise.resolve({}), + list: () => Promise.resolve([]), withTransaction: function () { return this }, diff --git a/packages/medusa/src/services/line-item.ts b/packages/medusa/src/services/line-item.ts index 6a4bad67aa..f1314a31ee 100644 --- a/packages/medusa/src/services/line-item.ts +++ b/packages/medusa/src/services/line-item.ts @@ -201,7 +201,7 @@ class LineItemService extends TransactionBaseService { ? LineItem : LineItem[] >( - variantIdOrData: string | T, + variantIdOrData: T, regionIdOrContext: T extends string ? string : GenerateLineItemContext, quantity?: number, context: GenerateLineItemContext = {} diff --git a/packages/medusa/src/services/swap.ts b/packages/medusa/src/services/swap.ts index 96b11cbca8..444ea68768 100644 --- a/packages/medusa/src/services/swap.ts +++ b/packages/medusa/src/services/swap.ts @@ -1,11 +1,11 @@ import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" +import { EntityManager, In } from "typeorm" import { buildQuery, setMetadata, validateId } from "../utils" import { TransactionBaseService } from "../interfaces" import LineItemAdjustmentService from "./line-item-adjustment" -import { FindConfig, Selector } from "../types/common" +import { FindConfig, Selector, WithRequiredProperty } from "../types/common" import { SwapRepository } from "../repositories/swap" import CartService from "./cart" import { @@ -314,7 +314,7 @@ class SwapService extends TransactionBaseService { */ async create( order: Order, - returnItems: Partial[], + returnItems: WithRequiredProperty, "item_id">[], additionalItems?: Pick[], returnShipping?: { option_id: string; price?: number }, custom: { @@ -335,22 +335,13 @@ class SwapService extends TransactionBaseService { ) } - const lineItemServiceTx = this.lineItemService_.withTransaction(manager) - for (const item of returnItems) { - const line = await lineItemServiceTx.retrieve(item.item_id!, { - relations: ["order", "swap", "claim_order"], - }) + const areReturnItemsValid = await this.areReturnItemsValid(returnItems) - if ( - line.order?.canceled_at || - line.swap?.canceled_at || - line.claim_order?.canceled_at - ) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Cannot create a swap on a canceled item.` - ) - } + if (!areReturnItemsValid) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + `Cannot create a swap on a canceled item.` + ) } let newItems: LineItem[] = [] @@ -364,9 +355,13 @@ class SwapService extends TransactionBaseService { "You must include a variant when creating additional items on a swap" ) } - return this.lineItemService_ - .withTransaction(manager) - .generate(variant_id, order.region_id, quantity) + return this.lineItemService_.withTransaction(manager).generate( + { variantId: variant_id, quantity }, + { + region_id: order.region_id, + cart: order.cart, + } + ) }) ) } @@ -1221,6 +1216,33 @@ class SwapService extends TransactionBaseService { return result }) } + + protected async areReturnItemsValid( + returnItems: WithRequiredProperty, "item_id">[] + ): Promise { + const manager = this.transactionManager_ ?? this.manager_ + + const returnItemsEntities = await this.lineItemService_ + .withTransaction(manager) + .list( + { + id: In(returnItems.map((r) => r.item_id)), + }, + { + relations: ["order", "swap", "claim_order"], + } + ) + + const hasCanceledItem = returnItemsEntities.some((item) => { + return ( + item.order?.canceled_at || + item.swap?.canceled_at || + item.claim_order?.canceled_at + ) + }) + + return !hasCanceledItem + } } export default SwapService