feat(utils,types): added item/shipping adjustments for order/items/shipping_methods (#6050)
what: - adds compute actions for the following cases: - items => each & across - shipping_method => each & across - order - adds a remove compute actions when code is no longer present in adjustments array RESOLVES CORE-1625 RESOLVES CORE-1626 RESOLVES CORE-1627 RESOLVES CORE-1628 RESOLVES CORE-1585
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
export * from "./items"
|
||||
export * from "./order"
|
||||
export * from "./shipping-methods"
|
||||
@@ -0,0 +1,131 @@
|
||||
import {
|
||||
ApplicationMethodAllocationValues,
|
||||
PromotionTypes,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
ApplicationMethodAllocation,
|
||||
ApplicationMethodTargetType,
|
||||
MedusaError,
|
||||
} from "@medusajs/utils"
|
||||
import { areRulesValidForContext } from "../validations"
|
||||
|
||||
export function getComputedActionsForItems(
|
||||
promotion: PromotionTypes.PromotionDTO,
|
||||
itemApplicationContext: PromotionTypes.ComputeActionContext[ApplicationMethodTargetType.ITEMS],
|
||||
methodIdPromoValueMap: Map<string, number>,
|
||||
allocationOverride?: ApplicationMethodAllocationValues
|
||||
): PromotionTypes.ComputeActions[] {
|
||||
const applicableItems: PromotionTypes.ComputeActionContext[ApplicationMethodTargetType.ITEMS] =
|
||||
[]
|
||||
|
||||
if (!itemApplicationContext) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`"items" should be present as an array in the context for computeActions`
|
||||
)
|
||||
}
|
||||
|
||||
for (const itemContext of itemApplicationContext) {
|
||||
const isPromotionApplicableToItem = areRulesValidForContext(
|
||||
promotion?.application_method?.target_rules!,
|
||||
itemContext
|
||||
)
|
||||
|
||||
if (!isPromotionApplicableToItem) {
|
||||
continue
|
||||
}
|
||||
|
||||
applicableItems.push(itemContext)
|
||||
}
|
||||
|
||||
return applyPromotionToItems(
|
||||
promotion,
|
||||
applicableItems,
|
||||
methodIdPromoValueMap,
|
||||
allocationOverride
|
||||
)
|
||||
}
|
||||
|
||||
export function applyPromotionToItems(
|
||||
promotion: PromotionTypes.PromotionDTO,
|
||||
items: PromotionTypes.ComputeActionContext[ApplicationMethodTargetType.ITEMS],
|
||||
methodIdPromoValueMap: Map<string, number>,
|
||||
allocationOverride?: ApplicationMethodAllocationValues
|
||||
): PromotionTypes.ComputeActions[] {
|
||||
const { application_method: applicationMethod } = promotion
|
||||
const allocation = applicationMethod?.allocation!
|
||||
const computedActions: PromotionTypes.ComputeActions[] = []
|
||||
|
||||
if (
|
||||
[allocation, allocationOverride].includes(ApplicationMethodAllocation.EACH)
|
||||
) {
|
||||
for (const method of items!) {
|
||||
const appliedPromoValue = methodIdPromoValueMap.get(method.id) || 0
|
||||
const promotionValue = parseFloat(applicationMethod!.value!)
|
||||
const applicableTotal =
|
||||
method.unit_price *
|
||||
Math.min(method.quantity, applicationMethod?.max_quantity!) -
|
||||
appliedPromoValue
|
||||
|
||||
const amount = Math.min(promotionValue, applicableTotal)
|
||||
|
||||
if (amount <= 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
methodIdPromoValueMap.set(method.id, appliedPromoValue + amount)
|
||||
|
||||
computedActions.push({
|
||||
action: "addItemAdjustment",
|
||||
item_id: method.id,
|
||||
amount,
|
||||
code: promotion.code!,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
[allocation, allocationOverride].includes(
|
||||
ApplicationMethodAllocation.ACROSS
|
||||
)
|
||||
) {
|
||||
const totalApplicableValue = items!.reduce((acc, method) => {
|
||||
const appliedPromoValue = methodIdPromoValueMap.get(method.id) || 0
|
||||
return (
|
||||
acc +
|
||||
method.unit_price *
|
||||
Math.min(method.quantity, applicationMethod?.max_quantity!) -
|
||||
appliedPromoValue
|
||||
)
|
||||
}, 0)
|
||||
|
||||
for (const method of items!) {
|
||||
const promotionValue = parseFloat(applicationMethod!.value!)
|
||||
const appliedPromoValue = methodIdPromoValueMap.get(method.id) || 0
|
||||
|
||||
const applicableTotal =
|
||||
method.unit_price *
|
||||
Math.min(method.quantity, applicationMethod?.max_quantity!) -
|
||||
appliedPromoValue
|
||||
|
||||
// TODO: should we worry about precision here?
|
||||
const applicablePromotionValue =
|
||||
(applicableTotal / totalApplicableValue) * promotionValue
|
||||
|
||||
const amount = Math.min(applicablePromotionValue, applicableTotal)
|
||||
|
||||
if (amount <= 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
computedActions.push({
|
||||
action: "addItemAdjustment",
|
||||
item_id: method.id,
|
||||
amount,
|
||||
code: promotion.code!,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return computedActions
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { PromotionTypes } from "@medusajs/types"
|
||||
import {
|
||||
ApplicationMethodAllocation,
|
||||
ApplicationMethodTargetType,
|
||||
} from "@medusajs/utils"
|
||||
import { getComputedActionsForItems } from "./items"
|
||||
|
||||
export function getComputedActionsForOrder(
|
||||
promotion: PromotionTypes.PromotionDTO,
|
||||
itemApplicationContext: PromotionTypes.ComputeActionContext,
|
||||
methodIdPromoValueMap: Map<string, number>
|
||||
): PromotionTypes.ComputeActions[] {
|
||||
return getComputedActionsForItems(
|
||||
promotion,
|
||||
itemApplicationContext[ApplicationMethodTargetType.ITEMS],
|
||||
methodIdPromoValueMap,
|
||||
ApplicationMethodAllocation.ACROSS
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
import { PromotionTypes } from "@medusajs/types"
|
||||
import {
|
||||
ApplicationMethodAllocation,
|
||||
ApplicationMethodTargetType,
|
||||
MedusaError,
|
||||
} from "@medusajs/utils"
|
||||
import { areRulesValidForContext } from "../validations"
|
||||
|
||||
export function getComputedActionsForShippingMethods(
|
||||
promotion: PromotionTypes.PromotionDTO,
|
||||
shippingMethodApplicationContext: PromotionTypes.ComputeActionContext[ApplicationMethodTargetType.SHIPPING_METHODS],
|
||||
methodIdPromoValueMap: Map<string, number>
|
||||
): PromotionTypes.ComputeActions[] {
|
||||
const applicableShippingItems: PromotionTypes.ComputeActionContext[ApplicationMethodTargetType.SHIPPING_METHODS] =
|
||||
[]
|
||||
|
||||
if (!shippingMethodApplicationContext) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`"shipping_methods" should be present as an array in the context for computeActions`
|
||||
)
|
||||
}
|
||||
|
||||
for (const shippingMethodContext of shippingMethodApplicationContext) {
|
||||
const isPromotionApplicableToItem = areRulesValidForContext(
|
||||
promotion.application_method?.target_rules!,
|
||||
shippingMethodContext
|
||||
)
|
||||
|
||||
if (!isPromotionApplicableToItem) {
|
||||
continue
|
||||
}
|
||||
|
||||
applicableShippingItems.push(shippingMethodContext)
|
||||
}
|
||||
|
||||
return applyPromotionToShippingMethods(
|
||||
promotion,
|
||||
applicableShippingItems,
|
||||
methodIdPromoValueMap
|
||||
)
|
||||
}
|
||||
|
||||
export function applyPromotionToShippingMethods(
|
||||
promotion: PromotionTypes.PromotionDTO,
|
||||
shippingMethods: PromotionTypes.ComputeActionContext[ApplicationMethodTargetType.SHIPPING_METHODS],
|
||||
methodIdPromoValueMap: Map<string, number>
|
||||
): PromotionTypes.ComputeActions[] {
|
||||
const { application_method: applicationMethod } = promotion
|
||||
const allocation = applicationMethod?.allocation!
|
||||
const computedActions: PromotionTypes.ComputeActions[] = []
|
||||
|
||||
if (allocation === ApplicationMethodAllocation.EACH) {
|
||||
for (const method of shippingMethods!) {
|
||||
const appliedPromoValue = methodIdPromoValueMap.get(method.id) || 0
|
||||
const promotionValue = parseFloat(applicationMethod!.value!)
|
||||
const applicableTotal = method.unit_price - appliedPromoValue
|
||||
const amount = Math.min(promotionValue, applicableTotal)
|
||||
|
||||
if (amount <= 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
methodIdPromoValueMap.set(method.id, appliedPromoValue + amount)
|
||||
|
||||
computedActions.push({
|
||||
action: "addShippingMethodAdjustment",
|
||||
shipping_method_id: method.id,
|
||||
amount,
|
||||
code: promotion.code!,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (allocation === ApplicationMethodAllocation.ACROSS) {
|
||||
const totalApplicableValue = shippingMethods!.reduce((acc, method) => {
|
||||
const appliedPromoValue = methodIdPromoValueMap.get(method.id) || 0
|
||||
|
||||
return acc + method.unit_price - appliedPromoValue
|
||||
}, 0)
|
||||
|
||||
if (totalApplicableValue <= 0) {
|
||||
return computedActions
|
||||
}
|
||||
|
||||
for (const method of shippingMethods!) {
|
||||
const promotionValue = parseFloat(applicationMethod!.value!)
|
||||
const applicableTotal = method.unit_price
|
||||
const appliedPromoValue = methodIdPromoValueMap.get(method.id) || 0
|
||||
|
||||
// TODO: should we worry about precision here?
|
||||
const applicablePromotionValue =
|
||||
(applicableTotal / totalApplicableValue) * promotionValue -
|
||||
appliedPromoValue
|
||||
|
||||
const amount = Math.min(applicablePromotionValue, applicableTotal)
|
||||
|
||||
if (amount <= 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
methodIdPromoValueMap.set(method.id, appliedPromoValue + amount)
|
||||
|
||||
computedActions.push({
|
||||
action: "addShippingMethodAdjustment",
|
||||
shipping_method_id: method.id,
|
||||
amount,
|
||||
code: promotion.code!,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return computedActions
|
||||
}
|
||||
Reference in New Issue
Block a user