feat(core-flows, dashboard, fulfillment, fulfillment-manual, utils, types): create shipping options with calculated prices (#10495)
**What** - support creating SO with calculated price - support updating SO for both types of pricing - update `validateShippingOptionPricesStep` to handle both SO price_types - add the `validateShippingOptionsForPriceCalculation` method to `FulfillementModule` - add `canCalculate` and `calculatePrice` to fulfillment provider service service / interface / manual provider - disable SO pricing edit on Admin if SO price type is calculated --- CLOSES CMRC-776
This commit is contained in:
@@ -47,7 +47,10 @@ import {
|
|||||||
isOptionEnabledInStore,
|
isOptionEnabledInStore,
|
||||||
isReturnOption,
|
isReturnOption,
|
||||||
} from "../../../../../lib/shipping-options"
|
} from "../../../../../lib/shipping-options"
|
||||||
import { FulfillmentSetType } from "../../../common/constants"
|
import {
|
||||||
|
FulfillmentSetType,
|
||||||
|
ShippingOptionPriceType,
|
||||||
|
} from "../../../common/constants"
|
||||||
|
|
||||||
type LocationGeneralSectionProps = {
|
type LocationGeneralSectionProps = {
|
||||||
location: HttpTypes.AdminStockLocation
|
location: HttpTypes.AdminStockLocation
|
||||||
@@ -167,6 +170,8 @@ function ShippingOption({
|
|||||||
{
|
{
|
||||||
label: t("stockLocations.shippingOptions.pricing.action"),
|
label: t("stockLocations.shippingOptions.pricing.action"),
|
||||||
icon: <CurrencyDollar />,
|
icon: <CurrencyDollar />,
|
||||||
|
disabled:
|
||||||
|
option.price_type === ShippingOptionPriceType.Calculated,
|
||||||
to: `/settings/locations/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${option.service_zone_id}/shipping-option/${option.id}/pricing`,
|
to: `/settings/locations/${locationId}/fulfillment-set/${fulfillmentSetId}/service-zone/${option.service_zone_id}/shipping-option/${option.id}/pricing`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ interface PriceRegionId {
|
|||||||
|
|
||||||
export type SetShippingOptionsPricesStepInput = {
|
export type SetShippingOptionsPricesStepInput = {
|
||||||
id: string
|
id: string
|
||||||
prices?: FulfillmentWorkflow.UpdateShippingOptionsWorkflowInput["prices"]
|
prices?: FulfillmentWorkflow.UpdateShippingOptionPriceRecord[]
|
||||||
}[]
|
}[]
|
||||||
|
|
||||||
async function getCurrentShippingOptionPrices(
|
async function getCurrentShippingOptionPrices(
|
||||||
|
|||||||
@@ -1,26 +1,85 @@
|
|||||||
import { FulfillmentWorkflow } from "@medusajs/framework/types"
|
import { FulfillmentWorkflow } from "@medusajs/framework/types"
|
||||||
import { MedusaError, Modules } from "@medusajs/framework/utils"
|
import {
|
||||||
|
MedusaError,
|
||||||
|
Modules,
|
||||||
|
ShippingOptionPriceType,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
|
||||||
|
|
||||||
|
type OptionsInput = (
|
||||||
|
| FulfillmentWorkflow.CreateShippingOptionsWorkflowInput
|
||||||
|
| FulfillmentWorkflow.UpdateShippingOptionsWorkflowInput
|
||||||
|
)[]
|
||||||
|
|
||||||
export const validateShippingOptionPricesStepId =
|
export const validateShippingOptionPricesStepId =
|
||||||
"validate-shipping-option-prices"
|
"validate-shipping-option-prices"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate that regions exist for the shipping option prices.
|
* Validate that shipping options can be crated based on provided price configuration.
|
||||||
|
*
|
||||||
|
* For flat rate prices, it validates that regions exist for the shipping option prices.
|
||||||
|
* For calculated prices, it validates with the fulfillment provider if the price can be calculated.
|
||||||
*/
|
*/
|
||||||
export const validateShippingOptionPricesStep = createStep(
|
export const validateShippingOptionPricesStep = createStep(
|
||||||
validateShippingOptionPricesStepId,
|
validateShippingOptionPricesStepId,
|
||||||
async (
|
async (options: OptionsInput, { container }) => {
|
||||||
options: {
|
const fulfillmentModuleService = container.resolve(Modules.FULFILLMENT)
|
||||||
prices?: FulfillmentWorkflow.UpdateShippingOptionsWorkflowInput["prices"]
|
|
||||||
}[],
|
const optionIds = options.map(
|
||||||
{ container }
|
(option) =>
|
||||||
) => {
|
(option as FulfillmentWorkflow.UpdateShippingOptionsWorkflowInput).id
|
||||||
const allPrices = options.flatMap((option) => option.prices ?? [])
|
)
|
||||||
|
|
||||||
|
if (optionIds.length) {
|
||||||
|
/**
|
||||||
|
* This means we are validating an update of shipping options.
|
||||||
|
* We need to ensure that all shipping options have price_type set
|
||||||
|
* to correctly determine price updates.
|
||||||
|
*
|
||||||
|
* (On create, price_type must be defined already.)
|
||||||
|
*/
|
||||||
|
const shippingOptions =
|
||||||
|
await fulfillmentModuleService.listShippingOptions(
|
||||||
|
{
|
||||||
|
id: optionIds,
|
||||||
|
},
|
||||||
|
{ select: ["id", "price_type", "provider_id"] }
|
||||||
|
)
|
||||||
|
|
||||||
|
const optionsMap = new Map(
|
||||||
|
shippingOptions.map((option) => [option.id, option])
|
||||||
|
)
|
||||||
|
|
||||||
|
;(
|
||||||
|
options as FulfillmentWorkflow.UpdateShippingOptionsWorkflowInput[]
|
||||||
|
).forEach((option) => {
|
||||||
|
option.price_type =
|
||||||
|
option.price_type ?? optionsMap.get(option.id)?.price_type
|
||||||
|
option.provider_id =
|
||||||
|
option.provider_id ?? optionsMap.get(option.id)?.provider_id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const flatRatePrices: FulfillmentWorkflow.UpdateShippingOptionPriceRecord[] =
|
||||||
|
[]
|
||||||
|
const calculatedOptions: OptionsInput = []
|
||||||
|
|
||||||
|
options.forEach((option) => {
|
||||||
|
if (option.price_type === ShippingOptionPriceType.FLAT) {
|
||||||
|
flatRatePrices.push(...(option.prices ?? []))
|
||||||
|
}
|
||||||
|
if (option.price_type === ShippingOptionPriceType.CALCULATED) {
|
||||||
|
calculatedOptions.push(option)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await fulfillmentModuleService.validateShippingOptionsForPriceCalculation(
|
||||||
|
calculatedOptions as FulfillmentWorkflow.CreateShippingOptionsWorkflowInput[]
|
||||||
|
)
|
||||||
|
|
||||||
const regionIdSet = new Set<string>()
|
const regionIdSet = new Set<string>()
|
||||||
|
|
||||||
allPrices.forEach((price) => {
|
flatRatePrices.forEach((price) => {
|
||||||
if ("region_id" in price && price.region_id) {
|
if ("region_id" in price && price.region_id) {
|
||||||
regionIdSet.add(price.region_id)
|
regionIdSet.add(price.region_id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,13 @@ export const createShippingOptionsWorkflow = createWorkflow(
|
|||||||
|
|
||||||
const data = transform(input, (data) => {
|
const data = transform(input, (data) => {
|
||||||
const shippingOptionsIndexToPrices = data.map((option, index) => {
|
const shippingOptionsIndexToPrices = data.map((option, index) => {
|
||||||
const prices = option.prices
|
/**
|
||||||
|
* Flat rate ShippingOptions always needs to provide a price array.
|
||||||
|
*
|
||||||
|
* For calculated pricing we create an "empty" price set
|
||||||
|
* so we can have simpler update flow for both cases and allow updating price_type.
|
||||||
|
*/
|
||||||
|
const prices = (option as any).prices ?? []
|
||||||
return {
|
return {
|
||||||
shipping_option_index: index,
|
shipping_option_index: index,
|
||||||
prices,
|
prices,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
} from "../steps"
|
} from "../steps"
|
||||||
import { validateFulfillmentProvidersStep } from "../steps/validate-fulfillment-providers"
|
import { validateFulfillmentProvidersStep } from "../steps/validate-fulfillment-providers"
|
||||||
import { validateShippingOptionPricesStep } from "../steps/validate-shipping-option-prices"
|
import { validateShippingOptionPricesStep } from "../steps/validate-shipping-option-prices"
|
||||||
|
import { ShippingOptionPriceType } from "@medusajs/framework/utils"
|
||||||
|
|
||||||
export const updateShippingOptionsWorkflowId =
|
export const updateShippingOptionsWorkflowId =
|
||||||
"update-shipping-options-workflow"
|
"update-shipping-options-workflow"
|
||||||
@@ -32,11 +33,22 @@ export const updateShippingOptionsWorkflow = createWorkflow(
|
|||||||
|
|
||||||
const data = transform(input, (data) => {
|
const data = transform(input, (data) => {
|
||||||
const shippingOptionsIndexToPrices = data.map((option, index) => {
|
const shippingOptionsIndexToPrices = data.map((option, index) => {
|
||||||
const prices = option.prices
|
const prices = (
|
||||||
delete option.prices
|
option as FulfillmentWorkflow.UpdateFlatRateShippingOptionInput
|
||||||
|
).prices
|
||||||
|
|
||||||
|
delete (option as FulfillmentWorkflow.UpdateFlatRateShippingOptionInput)
|
||||||
|
.prices
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When we are updating an option to be calculated, remove the prices.
|
||||||
|
*/
|
||||||
|
const isCalculatedOption =
|
||||||
|
option.price_type === ShippingOptionPriceType.CALCULATED
|
||||||
|
|
||||||
return {
|
return {
|
||||||
shipping_option_index: index,
|
shipping_option_index: index,
|
||||||
prices,
|
prices: isCalculatedOption ? [] : prices,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -58,8 +70,10 @@ export const updateShippingOptionsWorkflow = createWorkflow(
|
|||||||
(data) => {
|
(data) => {
|
||||||
const shippingOptionsPrices = data.shippingOptionsIndexToPrices.map(
|
const shippingOptionsPrices = data.shippingOptionsIndexToPrices.map(
|
||||||
({ shipping_option_index, prices }) => {
|
({ shipping_option_index, prices }) => {
|
||||||
|
const option = data.shippingOptions[shipping_option_index]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: data.shippingOptions[shipping_option_index].id,
|
id: option.id,
|
||||||
prices,
|
prices,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ export type FulfillmentOption = {
|
|||||||
[k: string]: unknown
|
[k: string]: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CalculatedShippingOptionPrice = {
|
||||||
|
calculated_amount: number
|
||||||
|
is_calculated_price_tax_inclusive: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export interface IFulfillmentProvider {
|
export interface IFulfillmentProvider {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -41,7 +46,7 @@ export interface IFulfillmentProvider {
|
|||||||
*
|
*
|
||||||
* Check if the provider can calculate the fulfillment price.
|
* Check if the provider can calculate the fulfillment price.
|
||||||
*/
|
*/
|
||||||
canCalculate(data: Record<string, unknown>): Promise<any>
|
canCalculate(data: Record<string, unknown>): Promise<boolean>
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Calculate the price for the given fulfillment option.
|
* Calculate the price for the given fulfillment option.
|
||||||
@@ -50,7 +55,7 @@ export interface IFulfillmentProvider {
|
|||||||
optionData: Record<string, unknown>,
|
optionData: Record<string, unknown>,
|
||||||
data: Record<string, unknown>,
|
data: Record<string, unknown>,
|
||||||
context: Record<string, unknown>
|
context: Record<string, unknown>
|
||||||
): Promise<any>
|
): Promise<CalculatedShippingOptionPrice>
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Create a fulfillment for the given data.
|
* Create a fulfillment for the given data.
|
||||||
|
|||||||
@@ -2625,6 +2625,28 @@ export interface IFulfillmentModuleService extends IModuleService {
|
|||||||
context: Record<string, unknown>
|
context: Record<string, unknown>
|
||||||
): Promise<boolean>
|
): Promise<boolean>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks whether a shipping option can have calculated price.
|
||||||
|
*
|
||||||
|
* @param {FulfillmentTypes.CreateShippingOptionDTO[]} shippingOptionsData - The shipping options data to check.
|
||||||
|
* @returns {Promise<boolean[]>} Whether the shipping options can have calculated price.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const isValid =
|
||||||
|
* await fulfillmentModuleService.validateShippingOptionsForPriceCalculation(
|
||||||
|
* [
|
||||||
|
* {
|
||||||
|
* provider_id: "webshipper",
|
||||||
|
* price_type: "calculated",
|
||||||
|
* },
|
||||||
|
* ]
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
validateShippingOptionsForPriceCalculation(
|
||||||
|
shippingOptionsData: CreateShippingOptionDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<boolean[]>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method retrieves a paginated list of fulfillment providers based on optional filters and configuration.
|
* This method retrieves a paginated list of fulfillment providers based on optional filters and configuration.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,28 +1,27 @@
|
|||||||
import { ShippingOptionDTO, ShippingOptionPriceType } from "../../fulfillment"
|
import { ShippingOptionDTO } from "../../fulfillment"
|
||||||
import { RuleOperatorType } from "../../common"
|
import { RuleOperatorType } from "../../common"
|
||||||
|
|
||||||
export interface CreateShippingOptionsWorkflowInput {
|
type CreateFlatRateShippingOptionPriceRecord =
|
||||||
|
| {
|
||||||
|
currency_code: string
|
||||||
|
amount: number
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
region_id: string
|
||||||
|
amount: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateFlatShippingOptionInputBase = {
|
||||||
name: string
|
name: string
|
||||||
service_zone_id: string
|
service_zone_id: string
|
||||||
shipping_profile_id: string
|
shipping_profile_id: string
|
||||||
data?: Record<string, unknown>
|
data?: Record<string, unknown>
|
||||||
price_type: ShippingOptionPriceType
|
|
||||||
provider_id: string
|
provider_id: string
|
||||||
type: {
|
type: {
|
||||||
label: string
|
label: string
|
||||||
description: string
|
description: string
|
||||||
code: string
|
code: string
|
||||||
}
|
}
|
||||||
prices: (
|
|
||||||
| {
|
|
||||||
currency_code: string
|
|
||||||
amount: number
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
region_id: string
|
|
||||||
amount: number
|
|
||||||
}
|
|
||||||
)[]
|
|
||||||
rules?: {
|
rules?: {
|
||||||
attribute: string
|
attribute: string
|
||||||
operator: RuleOperatorType
|
operator: RuleOperatorType
|
||||||
@@ -30,4 +29,17 @@ export interface CreateShippingOptionsWorkflowInput {
|
|||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateFlatRateShippingOptionInput = CreateFlatShippingOptionInputBase & {
|
||||||
|
price_type: "flat"
|
||||||
|
prices: CreateFlatRateShippingOptionPriceRecord[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateCalculatedShippingOptionInput = CreateFlatShippingOptionInputBase & {
|
||||||
|
price_type: "calculated"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreateShippingOptionsWorkflowInput =
|
||||||
|
| CreateFlatRateShippingOptionInput
|
||||||
|
| CreateCalculatedShippingOptionInput
|
||||||
|
|
||||||
export type CreateShippingOptionsWorkflowOutput = ShippingOptionDTO[]
|
export type CreateShippingOptionsWorkflowOutput = ShippingOptionDTO[]
|
||||||
|
|||||||
@@ -1,34 +1,18 @@
|
|||||||
import { RuleOperatorType } from "../../common"
|
import { RuleOperatorType } from "../../common"
|
||||||
import { ShippingOptionPriceType } from "../../fulfillment"
|
|
||||||
import { PriceRule } from "../../pricing"
|
import { PriceRule } from "../../pricing"
|
||||||
|
|
||||||
export interface UpdateShippingOptionsWorkflowInput {
|
type UpdateFlatShippingOptionInputBase = {
|
||||||
id: string
|
id: string
|
||||||
name?: string
|
name?: string
|
||||||
service_zone_id?: string
|
service_zone_id?: string
|
||||||
shipping_profile_id?: string
|
shipping_profile_id?: string
|
||||||
data?: Record<string, unknown>
|
data?: Record<string, unknown>
|
||||||
price_type?: ShippingOptionPriceType
|
|
||||||
provider_id?: string
|
provider_id?: string
|
||||||
type?: {
|
type?: {
|
||||||
label: string
|
label: string
|
||||||
description: string
|
description: string
|
||||||
code: string
|
code: string
|
||||||
}
|
}
|
||||||
prices?: (
|
|
||||||
| {
|
|
||||||
id?: string
|
|
||||||
currency_code?: string
|
|
||||||
amount?: number
|
|
||||||
rules?: PriceRule[]
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
id?: string
|
|
||||||
region_id?: string
|
|
||||||
amount?: number
|
|
||||||
rules?: PriceRule[]
|
|
||||||
}
|
|
||||||
)[]
|
|
||||||
rules?: {
|
rules?: {
|
||||||
attribute: string
|
attribute: string
|
||||||
operator: RuleOperatorType
|
operator: RuleOperatorType
|
||||||
@@ -36,6 +20,35 @@ export interface UpdateShippingOptionsWorkflowInput {
|
|||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type UpdateShippingOptionPriceRecord =
|
||||||
|
| {
|
||||||
|
id?: string
|
||||||
|
currency_code?: string
|
||||||
|
amount?: number
|
||||||
|
rules?: PriceRule[]
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id?: string
|
||||||
|
region_id?: string
|
||||||
|
amount?: number
|
||||||
|
rules?: PriceRule[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateCalculatedShippingOptionInput =
|
||||||
|
UpdateFlatShippingOptionInputBase & {
|
||||||
|
price_type?: "calculated"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateFlatRateShippingOptionInput =
|
||||||
|
UpdateFlatShippingOptionInputBase & {
|
||||||
|
price_type?: "flat"
|
||||||
|
prices?: UpdateShippingOptionPriceRecord[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateShippingOptionsWorkflowInput =
|
||||||
|
| UpdateFlatRateShippingOptionInput
|
||||||
|
| UpdateCalculatedShippingOptionInput
|
||||||
|
|
||||||
export type UpdateShippingOptionsWorkflowOutput = {
|
export type UpdateShippingOptionsWorkflowOutput = {
|
||||||
id: string
|
id: string
|
||||||
}[]
|
}[]
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { FulfillmentOption, IFulfillmentProvider } from "@medusajs/types"
|
import {
|
||||||
|
CalculatedShippingOptionPrice,
|
||||||
|
FulfillmentOption,
|
||||||
|
IFulfillmentProvider,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ### constructor
|
* ### constructor
|
||||||
@@ -221,7 +225,7 @@ export class AbstractFulfillmentProviderService
|
|||||||
optionData: Record<string, unknown>,
|
optionData: Record<string, unknown>,
|
||||||
data: Record<string, unknown>,
|
data: Record<string, unknown>,
|
||||||
context: Record<string, unknown>
|
context: Record<string, unknown>
|
||||||
): Promise<number> {
|
): Promise<CalculatedShippingOptionPrice> {
|
||||||
throw Error("calculatePrice must be overridden by the child class")
|
throw Error("calculatePrice must be overridden by the child class")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,7 +349,9 @@ export class AbstractFulfillmentProviderService
|
|||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
async createReturnFulfillment(fulfillment: Record<string, unknown>): Promise<any> {
|
async createReturnFulfillment(
|
||||||
|
fulfillment: Record<string, unknown>
|
||||||
|
): Promise<any> {
|
||||||
throw Error("createReturn must be overridden by the child class")
|
throw Error("createReturn must be overridden by the child class")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1970,6 +1970,34 @@ export default class FulfillmentModuleService
|
|||||||
return !!shippingOptions.length
|
return !!shippingOptions.length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@InjectManager()
|
||||||
|
async validateShippingOptionsForPriceCalculation(
|
||||||
|
shippingOptionsData: FulfillmentTypes.CreateShippingOptionDTO[],
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<boolean[]> {
|
||||||
|
const nonCalculatedOptions = shippingOptionsData.filter(
|
||||||
|
(option) => option.price_type !== "calculated"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (nonCalculatedOptions.length) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Cannot calculate price for non-calculated shipping options: ${nonCalculatedOptions
|
||||||
|
.map((o) => o.name)
|
||||||
|
.join(", ")}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const promises = shippingOptionsData.map((option) =>
|
||||||
|
this.fulfillmentProviderService_.canCalculate(
|
||||||
|
option.provider_id,
|
||||||
|
option as unknown as Record<string, unknown>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return await promiseAll(promises)
|
||||||
|
}
|
||||||
|
|
||||||
@InjectTransactionManager()
|
@InjectTransactionManager()
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
async deleteShippingProfiles(
|
async deleteShippingProfiles(
|
||||||
|
|||||||
@@ -100,6 +100,21 @@ export default class FulfillmentProviderService extends ModulesSdkUtils.MedusaIn
|
|||||||
return await provider.validateOption(data)
|
return await provider.validateOption(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async canCalculate(providerId: string, data: Record<string, unknown>) {
|
||||||
|
const provider = this.retrieveProviderRegistration(providerId)
|
||||||
|
return await provider.canCalculate(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
async calculatePrice(
|
||||||
|
providerId: string,
|
||||||
|
optionData: Record<string, unknown>,
|
||||||
|
data: Record<string, unknown>,
|
||||||
|
context: Record<string, unknown>
|
||||||
|
) {
|
||||||
|
const provider = this.retrieveProviderRegistration(providerId)
|
||||||
|
return await provider.calculatePrice(optionData, data, context)
|
||||||
|
}
|
||||||
|
|
||||||
async createFulfillment(
|
async createFulfillment(
|
||||||
providerId: string,
|
providerId: string,
|
||||||
data: object,
|
data: object,
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { AbstractFulfillmentProviderService } from "@medusajs/framework/utils"
|
import { AbstractFulfillmentProviderService } from "@medusajs/framework/utils"
|
||||||
import { FulfillmentOption } from "@medusajs/types"
|
import {
|
||||||
|
CalculatedShippingOptionPrice,
|
||||||
|
FulfillmentOption,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
|
||||||
// TODO rework type and DTO's
|
// TODO rework type and DTO's
|
||||||
|
|
||||||
@@ -30,6 +33,18 @@ export class ManualFulfillmentService extends AbstractFulfillmentProviderService
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async calculatePrice(
|
||||||
|
optionData: Record<string, unknown>,
|
||||||
|
data: Record<string, unknown>,
|
||||||
|
context: Record<string, unknown>
|
||||||
|
): Promise<CalculatedShippingOptionPrice> {
|
||||||
|
throw new Error("Manual fulfillment does not support price calculation")
|
||||||
|
}
|
||||||
|
|
||||||
|
async canCalculate(): Promise<boolean> {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
async validateOption(data: Record<string, any>): Promise<boolean> {
|
async validateOption(data: Record<string, any>): Promise<boolean> {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user