fix(medusa): Throw on flat rate shipping options with no amount (#2628)
This commit is contained in:
1 parent
e63777e3c5
commit
b2ea8b7d45
8 files changed
+172
-68
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(medusa): Throw on flat rate shipping options with no amount
|
||||||
@@ -28,7 +28,7 @@ describe("/admin/shipping-options", () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||||
dbConnection = await initDb({ cwd })
|
dbConnection = await initDb({ cwd })
|
||||||
medusaProcess = await setupServer({ cwd })
|
medusaProcess = await setupServer({ cwd, verbose: false })
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
|||||||
@@ -14,15 +14,16 @@ const {
|
|||||||
|
|
||||||
jest.setTimeout(30000)
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
|
const adminReqConfig = {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
describe("Order Totals", () => {
|
describe("Order Totals", () => {
|
||||||
let medusaProcess
|
let medusaProcess
|
||||||
let dbConnection
|
let dbConnection
|
||||||
|
|
||||||
const doAfterEach = async () => {
|
|
||||||
const db = useDb()
|
|
||||||
return await db.teardown()
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||||
dbConnection = await initDb({ cwd })
|
dbConnection = await initDb({ cwd })
|
||||||
@@ -36,18 +37,26 @@ describe("Order Totals", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
return await doAfterEach()
|
const db = useDb()
|
||||||
|
await db.teardown()
|
||||||
})
|
})
|
||||||
|
|
||||||
test("calculates totals correctly for order with non-taxable gift card", async () => {
|
describe("GET /admin/orders/:id/totals", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
await adminSeeder(dbConnection)
|
||||||
|
|
||||||
await simpleProductFactory(dbConnection, {
|
await simpleProductFactory(dbConnection, {
|
||||||
variants: [
|
variants: [
|
||||||
{ id: "variant_1", prices: [{ currency: "usd", amount: 95600 }] },
|
{ id: "variant_1", prices: [{ currency: "usd", amount: 95600 }] },
|
||||||
{ id: "variant_2", prices: [{ currency: "usd", amount: 79600 }] },
|
{ id: "variant_2", prices: [{ currency: "usd", amount: 79600 }] },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("calculates totals correctly for order with non-taxable gift card", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
// Seed data
|
||||||
const region = await simpleRegionFactory(dbConnection, {
|
const region = await simpleRegionFactory(dbConnection, {
|
||||||
gift_cards_taxable: false,
|
gift_cards_taxable: false,
|
||||||
tax_rate: 25,
|
tax_rate: 25,
|
||||||
@@ -66,28 +75,35 @@ describe("Order Totals", () => {
|
|||||||
balance: 160000,
|
balance: 160000,
|
||||||
})
|
})
|
||||||
|
|
||||||
const api = useApi()
|
// Add variant 1 to cart
|
||||||
|
|
||||||
await api.post("/store/carts/test-cart/line-items", {
|
await api.post("/store/carts/test-cart/line-items", {
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
variant_id: "variant_1",
|
variant_id: "variant_1",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Add variant 2 to cart
|
||||||
await api.post("/store/carts/test-cart/line-items", {
|
await api.post("/store/carts/test-cart/line-items", {
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
variant_id: "variant_2",
|
variant_id: "variant_2",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Add gift card to cart
|
||||||
await api.post("/store/carts/test-cart", {
|
await api.post("/store/carts/test-cart", {
|
||||||
gift_cards: [{ code: giftCard.code }],
|
gift_cards: [{ code: giftCard.code }],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Init payment sessions
|
||||||
await api.post(`/store/carts/${cart.id}/payment-sessions`)
|
await api.post(`/store/carts/${cart.id}/payment-sessions`)
|
||||||
|
|
||||||
|
// Complete cart
|
||||||
const response = await api.post(`/store/carts/test-cart/complete`)
|
const response = await api.post(`/store/carts/test-cart/complete`)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.type).toEqual("order")
|
expect(response.data.type).toEqual("order")
|
||||||
const orderId = response.data.data.id
|
const orderId = response.data.data.id
|
||||||
|
|
||||||
const { data } = await api.get(`/admin/orders/${orderId}`, {
|
// Retrieve the completed order
|
||||||
headers: { Authorization: `Bearer test_token` },
|
const { data } = await api.get(`/admin/orders/${orderId}`, adminReqConfig)
|
||||||
})
|
|
||||||
|
|
||||||
expect(data.order.gift_card_transactions).toHaveLength(1)
|
expect(data.order.gift_card_transactions).toHaveLength(1)
|
||||||
expect(data.order.gift_card_transactions).toEqual(
|
expect(data.order.gift_card_transactions).toEqual(
|
||||||
@@ -104,15 +120,9 @@ describe("Order Totals", () => {
|
|||||||
expect(data.order.total).toEqual(59000)
|
expect(data.order.total).toEqual(59000)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("calculates totals correctly for order with taxable gift card", async () => {
|
it("calculates totals correctly for order with taxable gift card", async () => {
|
||||||
await adminSeeder(dbConnection)
|
const api = useApi()
|
||||||
await simpleProductFactory(dbConnection, {
|
// Seed data
|
||||||
variants: [
|
|
||||||
{ id: "variant_1", prices: [{ currency: "usd", amount: 95600 }] },
|
|
||||||
{ id: "variant_2", prices: [{ currency: "usd", amount: 79600 }] },
|
|
||||||
],
|
|
||||||
})
|
|
||||||
|
|
||||||
const region = await simpleRegionFactory(dbConnection, {
|
const region = await simpleRegionFactory(dbConnection, {
|
||||||
gift_cards_taxable: true,
|
gift_cards_taxable: true,
|
||||||
tax_rate: 25,
|
tax_rate: 25,
|
||||||
@@ -131,28 +141,35 @@ describe("Order Totals", () => {
|
|||||||
balance: 160000,
|
balance: 160000,
|
||||||
})
|
})
|
||||||
|
|
||||||
const api = useApi()
|
// Add variant 1 to cart
|
||||||
|
|
||||||
await api.post("/store/carts/test-cart/line-items", {
|
await api.post("/store/carts/test-cart/line-items", {
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
variant_id: "variant_1",
|
variant_id: "variant_1",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Add variant 2 to cart
|
||||||
await api.post("/store/carts/test-cart/line-items", {
|
await api.post("/store/carts/test-cart/line-items", {
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
variant_id: "variant_2",
|
variant_id: "variant_2",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Add gift card to cart
|
||||||
await api.post("/store/carts/test-cart", {
|
await api.post("/store/carts/test-cart", {
|
||||||
gift_cards: [{ code: giftCard.code }],
|
gift_cards: [{ code: giftCard.code }],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Init payment sessions
|
||||||
await api.post(`/store/carts/${cart.id}/payment-sessions`)
|
await api.post(`/store/carts/${cart.id}/payment-sessions`)
|
||||||
|
|
||||||
|
// Complete cart
|
||||||
const response = await api.post(`/store/carts/test-cart/complete`)
|
const response = await api.post(`/store/carts/test-cart/complete`)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.type).toEqual("order")
|
expect(response.data.type).toEqual("order")
|
||||||
const orderId = response.data.data.id
|
const orderId = response.data.data.id
|
||||||
|
|
||||||
const { data } = await api.get(`/admin/orders/${orderId}`, {
|
// Retrieve the completed order
|
||||||
headers: { Authorization: `Bearer test_token` },
|
const { data } = await api.get(`/admin/orders/${orderId}`, adminReqConfig)
|
||||||
})
|
|
||||||
|
|
||||||
expect(data.order.gift_card_transactions).toHaveLength(1)
|
expect(data.order.gift_card_transactions).toHaveLength(1)
|
||||||
expect(data.order.gift_card_transactions).toEqual(
|
expect(data.order.gift_card_transactions).toEqual(
|
||||||
@@ -169,4 +186,5 @@ describe("Order Totals", () => {
|
|||||||
expect(data.order.tax_total).toEqual(3800)
|
expect(data.order.tax_total).toEqual(3800)
|
||||||
expect(data.order.total).toEqual(19000)
|
expect(data.order.total).toEqual(19000)
|
||||||
})
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -129,7 +129,7 @@ export const simpleProductFactory = async (
|
|||||||
await simpleProductVariantFactory(connection, factoryData)
|
await simpleProductVariantFactory(connection, factoryData)
|
||||||
}
|
}
|
||||||
|
|
||||||
return manager.findOne(
|
return await manager.findOne(
|
||||||
Product,
|
Product,
|
||||||
{ id: prodId },
|
{ id: prodId },
|
||||||
{ relations: ["tags", "variants", "variants.prices"] }
|
{ relations: ["tags", "variants", "variants.prices"] }
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import _ from "lodash"
|
import { IdMap, MockManager, MockRepository } from "medusa-test-utils"
|
||||||
import { IdMap, MockRepository, MockManager } from "medusa-test-utils"
|
import TaxInclusivePricingFeatureFlag from "../../loaders/feature-flags/tax-inclusive-pricing"
|
||||||
|
import { FlagRouter } from "../../utils/flag-router"
|
||||||
import ShippingOptionService from "../shipping-option"
|
import ShippingOptionService from "../shipping-option"
|
||||||
import { FlagRouter } from "../../utils/flag-router";
|
|
||||||
import TaxInclusivePricingFeatureFlag from "../../loaders/feature-flags/tax-inclusive-pricing";
|
|
||||||
|
|
||||||
describe("ShippingOptionService", () => {
|
describe("ShippingOptionService", () => {
|
||||||
describe("retrieve", () => {
|
describe("retrieve", () => {
|
||||||
@@ -36,13 +35,20 @@ describe("ShippingOptionService", () => {
|
|||||||
provider_id: "no_calc",
|
provider_id: "no_calc",
|
||||||
})
|
})
|
||||||
case IdMap.getId("validId"):
|
case IdMap.getId("validId"):
|
||||||
|
return Promise.resolve({
|
||||||
|
provider_id: "provider",
|
||||||
|
amount: 100,
|
||||||
|
data: {
|
||||||
|
provider_data: "true",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
case "flat-rate-no-amount":
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
provider_id: "provider",
|
provider_id: "provider",
|
||||||
data: {
|
data: {
|
||||||
provider_data: "true",
|
provider_data: "true",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return Promise.resolve({})
|
return Promise.resolve({})
|
||||||
}
|
}
|
||||||
@@ -137,7 +143,7 @@ describe("ShippingOptionService", () => {
|
|||||||
it("sets flat rate price", async () => {
|
it("sets flat rate price", async () => {
|
||||||
await optionService.update(IdMap.getId("validId"), {
|
await optionService.update(IdMap.getId("validId"), {
|
||||||
price_type: "flat_rate",
|
price_type: "flat_rate",
|
||||||
amount: 100,
|
amount: 200,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(shippingOptionRepository.save).toHaveBeenCalledTimes(1)
|
expect(shippingOptionRepository.save).toHaveBeenCalledTimes(1)
|
||||||
@@ -147,7 +153,37 @@ describe("ShippingOptionService", () => {
|
|||||||
provider_data: "true",
|
provider_data: "true",
|
||||||
},
|
},
|
||||||
price_type: "flat_rate",
|
price_type: "flat_rate",
|
||||||
amount: 100,
|
amount: 200,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("throws on flat rate but no amount", async () => {
|
||||||
|
expect.assertions(1)
|
||||||
|
try {
|
||||||
|
await optionService.update(IdMap.getId("flat-rate-no-amount"), {
|
||||||
|
price_type: "flat_rate",
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
expect(error.message).toEqual(
|
||||||
|
"Shipping options of type `flat_rate` must have an `amount`"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sets a price to", async () => {
|
||||||
|
await optionService.update(IdMap.getId("validId"), {
|
||||||
|
price_type: "flat_rate",
|
||||||
|
amount: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(shippingOptionRepository.save).toHaveBeenCalledTimes(1)
|
||||||
|
expect(shippingOptionRepository.save).toHaveBeenCalledWith({
|
||||||
|
provider_id: "provider",
|
||||||
|
data: {
|
||||||
|
provider_data: "true",
|
||||||
|
},
|
||||||
|
price_type: "flat_rate",
|
||||||
|
amount: 0,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -158,10 +194,8 @@ describe("ShippingOptionService", () => {
|
|||||||
|
|
||||||
expect(fulfillmentProviderService.canCalculate).toHaveBeenCalledTimes(1)
|
expect(fulfillmentProviderService.canCalculate).toHaveBeenCalledTimes(1)
|
||||||
expect(fulfillmentProviderService.canCalculate).toHaveBeenCalledWith({
|
expect(fulfillmentProviderService.canCalculate).toHaveBeenCalledWith({
|
||||||
amount: null,
|
|
||||||
data: { provider_data: "true" },
|
data: { provider_data: "true" },
|
||||||
provider_id: "provider",
|
provider_id: "provider",
|
||||||
price_type: "calculated",
|
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(shippingOptionRepository.save).toHaveBeenCalledTimes(1)
|
expect(shippingOptionRepository.save).toHaveBeenCalledTimes(1)
|
||||||
@@ -645,7 +679,7 @@ describe("ShippingOptionService", () => {
|
|||||||
totalsService,
|
totalsService,
|
||||||
fulfillmentProviderService: providerService,
|
fulfillmentProviderService: providerService,
|
||||||
featureFlagRouter: new FlagRouter({
|
featureFlagRouter: new FlagRouter({
|
||||||
[TaxInclusivePricingFeatureFlag.key]: true
|
[TaxInclusivePricingFeatureFlag.key]: true,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -657,7 +691,7 @@ describe("ShippingOptionService", () => {
|
|||||||
await optionService.createShippingMethod("random_id", {}, { price: 10 })
|
await optionService.createShippingMethod("random_id", {}, { price: 10 })
|
||||||
expect(shippingMethodRepository.save).toHaveBeenCalledWith(
|
expect(shippingMethodRepository.save).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
includes_tax: true
|
includes_tax: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ type FulfillmentProviderContainer = MedusaContainer & {
|
|||||||
[key in `${FulfillmentProviderKey}`]: typeof BaseFulfillmentService
|
[key in `${FulfillmentProviderKey}`]: typeof BaseFulfillmentService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CalculateOptionPriceInput = {
|
||||||
|
provider_id: string
|
||||||
|
data: Record<string, unknown>
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helps retrive fulfillment providers
|
* Helps retrive fulfillment providers
|
||||||
*/
|
*/
|
||||||
@@ -118,7 +123,7 @@ class FulfillmentProviderService extends TransactionBaseService {
|
|||||||
) as unknown as Record<string, unknown>
|
) as unknown as Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
async canCalculate(option: ShippingOption): Promise<boolean> {
|
async canCalculate(option: CalculateOptionPriceInput): Promise<boolean> {
|
||||||
const provider = this.retrieveProvider(option.provider_id)
|
const provider = this.retrieveProvider(option.provider_id)
|
||||||
return provider.canCalculate(option.data) as unknown as boolean
|
return provider.canCalculate(option.data) as unknown as boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import { DeepPartial, EntityManager } from "typeorm"
|
import { EntityManager } from "typeorm"
|
||||||
import { TransactionBaseService } from "../interfaces"
|
import { TransactionBaseService } from "../interfaces"
|
||||||
|
import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing"
|
||||||
import {
|
import {
|
||||||
Cart,
|
Cart,
|
||||||
Order,
|
Order,
|
||||||
@@ -18,12 +19,12 @@ import {
|
|||||||
CreateShippingOptionInput,
|
CreateShippingOptionInput,
|
||||||
ShippingMethodUpdate,
|
ShippingMethodUpdate,
|
||||||
UpdateShippingOptionInput,
|
UpdateShippingOptionInput,
|
||||||
|
ValidatePriceTypeAndAmountInput,
|
||||||
} from "../types/shipping-options"
|
} from "../types/shipping-options"
|
||||||
import { buildQuery, isDefined, setMetadata } from "../utils"
|
import { buildQuery, isDefined, setMetadata } from "../utils"
|
||||||
|
import { FlagRouter } from "../utils/flag-router"
|
||||||
import FulfillmentProviderService from "./fulfillment-provider"
|
import FulfillmentProviderService from "./fulfillment-provider"
|
||||||
import RegionService from "./region"
|
import RegionService from "./region"
|
||||||
import { FlagRouter } from "../utils/flag-router"
|
|
||||||
import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing"
|
|
||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
manager: EntityManager
|
manager: EntityManager
|
||||||
@@ -397,6 +398,42 @@ class ShippingOptionService extends TransactionBaseService {
|
|||||||
return option
|
return option
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async validateAndMutatePrice(
|
||||||
|
option: ShippingOption | CreateShippingOptionInput,
|
||||||
|
priceInput: ValidatePriceTypeAndAmountInput
|
||||||
|
): Promise<Omit<ShippingOption, "beforeInsert"> | CreateShippingOptionInput> {
|
||||||
|
const option_:
|
||||||
|
| Omit<ShippingOption, "beforeInsert">
|
||||||
|
| CreateShippingOptionInput = { ...option }
|
||||||
|
|
||||||
|
if (isDefined(priceInput.amount)) {
|
||||||
|
option_.amount = priceInput.amount
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefined(priceInput.price_type)) {
|
||||||
|
option_.price_type = await this.validatePriceType_(
|
||||||
|
priceInput.price_type,
|
||||||
|
option_ as ShippingOption
|
||||||
|
)
|
||||||
|
|
||||||
|
if (priceInput.price_type === ShippingOptionPriceType.CALCULATED) {
|
||||||
|
option_.amount = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
option_.price_type === ShippingOptionPriceType.FLAT_RATE &&
|
||||||
|
(option_.amount == null || option_.amount < 0)
|
||||||
|
) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
"Shipping options of type `flat_rate` must have an `amount`"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return option_
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new shipping option. Used both for outbound and inbound shipping
|
* Creates a new shipping option. Used both for outbound and inbound shipping
|
||||||
* options. The difference is registered by the `is_return` field which
|
* options. The difference is registered by the `is_return` field which
|
||||||
@@ -406,8 +443,12 @@ class ShippingOptionService extends TransactionBaseService {
|
|||||||
*/
|
*/
|
||||||
async create(data: CreateShippingOptionInput): Promise<ShippingOption> {
|
async create(data: CreateShippingOptionInput): Promise<ShippingOption> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager) => {
|
||||||
|
const optionWithValidatedPrice = await this.validateAndMutatePrice(data, {
|
||||||
|
price_type: data.price_type,
|
||||||
|
})
|
||||||
|
|
||||||
const optionRepo = manager.getCustomRepository(this.optionRepository_)
|
const optionRepo = manager.getCustomRepository(this.optionRepository_)
|
||||||
const option = optionRepo.create(data as DeepPartial<ShippingOption>)
|
const option = optionRepo.create(optionWithValidatedPrice)
|
||||||
|
|
||||||
const region = await this.regionService_
|
const region = await this.regionService_
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
@@ -426,10 +467,6 @@ class ShippingOptionService extends TransactionBaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
option.price_type = await this.validatePriceType_(data.price_type, option)
|
|
||||||
option.amount =
|
|
||||||
data.price_type === "calculated" ? null : data.amount ?? null
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.featureFlagRouter_.isFeatureEnabled(
|
this.featureFlagRouter_.isFeatureEnabled(
|
||||||
TaxInclusivePricingFeatureFlag.key
|
TaxInclusivePricingFeatureFlag.key
|
||||||
@@ -440,7 +477,9 @@ class ShippingOptionService extends TransactionBaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isValid = await this.providerService_.validateOption(option)
|
const isValid = await this.providerService_.validateOption(
|
||||||
|
option as ShippingOption
|
||||||
|
)
|
||||||
|
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -496,7 +535,8 @@ class ShippingOptionService extends TransactionBaseService {
|
|||||||
): Promise<ShippingOptionPriceType> {
|
): Promise<ShippingOptionPriceType> {
|
||||||
if (
|
if (
|
||||||
!priceType ||
|
!priceType ||
|
||||||
(priceType !== "flat_rate" && priceType !== "calculated")
|
(priceType !== ShippingOptionPriceType.FLAT_RATE &&
|
||||||
|
priceType !== ShippingOptionPriceType.CALCULATED)
|
||||||
) {
|
) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
@@ -504,8 +544,11 @@ class ShippingOptionService extends TransactionBaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priceType === "calculated") {
|
if (priceType === ShippingOptionPriceType.CALCULATED) {
|
||||||
const canCalculate = await this.providerService_.canCalculate(option)
|
const canCalculate = await this.providerService_.canCalculate({
|
||||||
|
provider_id: option.provider_id,
|
||||||
|
data: option.data,
|
||||||
|
})
|
||||||
if (!canCalculate) {
|
if (!canCalculate) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
@@ -597,26 +640,20 @@ class ShippingOptionService extends TransactionBaseService {
|
|||||||
option.requirements = acc
|
option.requirements = acc
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDefined(update.price_type)) {
|
const optionWithValidatedPrice = await this.validateAndMutatePrice(
|
||||||
option.price_type = await this.validatePriceType_(
|
option,
|
||||||
update.price_type,
|
{
|
||||||
option
|
price_type: update.price_type,
|
||||||
|
amount: update.amount,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
if (update.price_type === "calculated") {
|
|
||||||
option.amount = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefined(update.amount) && option.price_type !== "calculated") {
|
|
||||||
option.amount = update.amount
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefined(update.name)) {
|
if (isDefined(update.name)) {
|
||||||
option.name = update.name
|
optionWithValidatedPrice.name = update.name
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDefined(update.admin_only)) {
|
if (isDefined(update.admin_only)) {
|
||||||
option.admin_only = update.admin_only
|
optionWithValidatedPrice.admin_only = update.admin_only
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -625,12 +662,12 @@ class ShippingOptionService extends TransactionBaseService {
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
if (typeof update.includes_tax !== "undefined") {
|
if (typeof update.includes_tax !== "undefined") {
|
||||||
option.includes_tax = update.includes_tax
|
optionWithValidatedPrice.includes_tax = update.includes_tax
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const optionRepo = manager.getCustomRepository(this.optionRepository_)
|
const optionRepo = manager.getCustomRepository(this.optionRepository_)
|
||||||
return await optionRepo.save(option)
|
return await optionRepo.save(optionWithValidatedPrice)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,3 +74,8 @@ export type UpdateShippingOptionInput = {
|
|||||||
data?: string
|
data?: string
|
||||||
includes_tax?: boolean
|
includes_tax?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ValidatePriceTypeAndAmountInput = {
|
||||||
|
amount?: number
|
||||||
|
price_type?: ShippingOptionPriceType
|
||||||
|
}
|
||||||
Reference in new issue
Block a user