chore(medusa): New totals calc. in Swap creation (#3191)

* feat(medusa): Cleanup swap creation flow

* revert test and package

* fix unit tests

* fix swap seeder that does not include the tax lines on the return line item

---------

Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Adrien de Peretti
2023-02-14 10:52:45 +01:00
committed by GitHub
parent 80452332d8
commit 5e0273a370
5 changed files with 85 additions and 38 deletions

View File

@@ -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,

View File

@@ -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",

View File

@@ -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
},

View File

@@ -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 = {}

View File

@@ -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<ReturnItem>[],
returnItems: WithRequiredProperty<Partial<ReturnItem>, "item_id">[],
additionalItems?: Pick<LineItem, "variant_id" | "quantity">[],
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<Partial<ReturnItem>, "item_id">[]
): Promise<boolean> {
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