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 PerettiandOliver Windall Juhl authored and GitHub committed 2023-02-14 10:52:45 +01:00
1 parent 80452332d8
commit 5e0273a370
5 files changed
+81 -34

No files matched your search

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