feat(utils,types): add registerUsages for promotions + computeActions consider usage (#6094)
RESOLVES CORE-1639 RESOLVES CORE-1640 RESOLVES CORE-1634
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
export * from "./items"
|
||||
export * from "./order"
|
||||
export * from "./shipping-methods"
|
||||
export * from "./usage"
|
||||
|
||||
@@ -5,9 +5,11 @@ import {
|
||||
import {
|
||||
ApplicationMethodAllocation,
|
||||
ApplicationMethodTargetType,
|
||||
ComputedActions,
|
||||
MedusaError,
|
||||
} from "@medusajs/utils"
|
||||
import { areRulesValidForContext } from "../validations"
|
||||
import { computeActionForBudgetExceeded } from "./usage"
|
||||
|
||||
export function getComputedActionsForItems(
|
||||
promotion: PromotionTypes.PromotionDTO,
|
||||
@@ -61,22 +63,35 @@ export function applyPromotionToItems(
|
||||
) {
|
||||
for (const method of items!) {
|
||||
const appliedPromoValue = methodIdPromoValueMap.get(method.id) || 0
|
||||
const promotionValue = parseFloat(applicationMethod!.value!)
|
||||
const quantityMultiplier = Math.min(
|
||||
method.quantity,
|
||||
applicationMethod?.max_quantity!
|
||||
)
|
||||
const promotionValue =
|
||||
parseFloat(applicationMethod!.value!) * quantityMultiplier
|
||||
const applicableTotal =
|
||||
method.unit_price *
|
||||
Math.min(method.quantity, applicationMethod?.max_quantity!) -
|
||||
appliedPromoValue
|
||||
|
||||
method.unit_price * quantityMultiplier - appliedPromoValue
|
||||
const amount = Math.min(promotionValue, applicableTotal)
|
||||
|
||||
if (amount <= 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
const budgetExceededAction = computeActionForBudgetExceeded(
|
||||
promotion,
|
||||
amount
|
||||
)
|
||||
|
||||
if (budgetExceededAction) {
|
||||
computedActions.push(budgetExceededAction)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
methodIdPromoValueMap.set(method.id, appliedPromoValue + amount)
|
||||
|
||||
computedActions.push({
|
||||
action: "addItemAdjustment",
|
||||
action: ComputedActions.ADD_ITEM_ADJUSTMENT,
|
||||
item_id: method.id,
|
||||
amount,
|
||||
code: promotion.code!,
|
||||
@@ -91,35 +106,37 @@ export function applyPromotionToItems(
|
||||
) {
|
||||
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
|
||||
)
|
||||
return acc + method.unit_price * method.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
|
||||
method.unit_price * method.quantity - appliedPromoValue
|
||||
|
||||
// TODO: should we worry about precision here?
|
||||
const applicablePromotionValue =
|
||||
(applicableTotal / totalApplicableValue) * promotionValue
|
||||
|
||||
const amount = Math.min(applicablePromotionValue, applicableTotal)
|
||||
|
||||
if (amount <= 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
const budgetExceededAction = computeActionForBudgetExceeded(
|
||||
promotion,
|
||||
amount
|
||||
)
|
||||
|
||||
if (budgetExceededAction) {
|
||||
computedActions.push(budgetExceededAction)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
computedActions.push({
|
||||
action: "addItemAdjustment",
|
||||
action: ComputedActions.ADD_ITEM_ADJUSTMENT,
|
||||
item_id: method.id,
|
||||
amount,
|
||||
code: promotion.code!,
|
||||
|
||||
@@ -2,9 +2,11 @@ import { PromotionTypes } from "@medusajs/types"
|
||||
import {
|
||||
ApplicationMethodAllocation,
|
||||
ApplicationMethodTargetType,
|
||||
ComputedActions,
|
||||
MedusaError,
|
||||
} from "@medusajs/utils"
|
||||
import { areRulesValidForContext } from "../validations"
|
||||
import { computeActionForBudgetExceeded } from "./usage"
|
||||
|
||||
export function getComputedActionsForShippingMethods(
|
||||
promotion: PromotionTypes.PromotionDTO,
|
||||
@@ -61,10 +63,21 @@ export function applyPromotionToShippingMethods(
|
||||
continue
|
||||
}
|
||||
|
||||
const budgetExceededAction = computeActionForBudgetExceeded(
|
||||
promotion,
|
||||
amount
|
||||
)
|
||||
|
||||
if (budgetExceededAction) {
|
||||
computedActions.push(budgetExceededAction)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
methodIdPromoValueMap.set(method.id, appliedPromoValue + amount)
|
||||
|
||||
computedActions.push({
|
||||
action: "addShippingMethodAdjustment",
|
||||
action: ComputedActions.ADD_SHIPPING_METHOD_ADJUSTMENT,
|
||||
shipping_method_id: method.id,
|
||||
amount,
|
||||
code: promotion.code!,
|
||||
@@ -99,10 +112,21 @@ export function applyPromotionToShippingMethods(
|
||||
continue
|
||||
}
|
||||
|
||||
const budgetExceededAction = computeActionForBudgetExceeded(
|
||||
promotion,
|
||||
amount
|
||||
)
|
||||
|
||||
if (budgetExceededAction) {
|
||||
computedActions.push(budgetExceededAction)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
methodIdPromoValueMap.set(method.id, appliedPromoValue + amount)
|
||||
|
||||
computedActions.push({
|
||||
action: "addShippingMethodAdjustment",
|
||||
action: ComputedActions.ADD_SHIPPING_METHOD_ADJUSTMENT,
|
||||
shipping_method_id: method.id,
|
||||
amount,
|
||||
code: promotion.code!,
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
CampaignBudgetExceededAction,
|
||||
ComputeActions,
|
||||
PromotionDTO,
|
||||
} from "@medusajs/types"
|
||||
import { CampaignBudgetType, ComputedActions } from "@medusajs/utils"
|
||||
|
||||
export function canRegisterUsage(computedAction: ComputeActions): boolean {
|
||||
return (
|
||||
[
|
||||
ComputedActions.ADD_ITEM_ADJUSTMENT,
|
||||
ComputedActions.ADD_SHIPPING_METHOD_ADJUSTMENT,
|
||||
] as string[]
|
||||
).includes(computedAction.action)
|
||||
}
|
||||
|
||||
export function computeActionForBudgetExceeded(
|
||||
promotion: PromotionDTO,
|
||||
amount: number
|
||||
): CampaignBudgetExceededAction | void {
|
||||
const campaignBudget = promotion.campaign?.budget
|
||||
|
||||
if (!campaignBudget) {
|
||||
return
|
||||
}
|
||||
|
||||
const campaignBudgetUsed = campaignBudget.used || 0
|
||||
const totalUsed =
|
||||
campaignBudget.type === CampaignBudgetType.SPEND
|
||||
? campaignBudgetUsed + amount
|
||||
: campaignBudgetUsed + 1
|
||||
|
||||
if (campaignBudget.limit && totalUsed > campaignBudget.limit) {
|
||||
return {
|
||||
action: ComputedActions.CAMPAIGN_BUDGET_EXCEEDED,
|
||||
code: promotion.code!,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
ApplicationMethodType,
|
||||
MedusaError,
|
||||
isDefined,
|
||||
isPresent,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
export const allowedAllocationTargetTypes: string[] = [
|
||||
@@ -33,6 +34,16 @@ export function validateApplicationMethodAttributes(data: {
|
||||
}) {
|
||||
const allTargetTypes: string[] = Object.values(ApplicationMethodTargetType)
|
||||
|
||||
if (
|
||||
data.allocation === ApplicationMethodAllocation.ACROSS &&
|
||||
isPresent(data.max_quantity)
|
||||
) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`application_method.max_quantity is not allowed to be set for allocation (${ApplicationMethodAllocation.ACROSS})`
|
||||
)
|
||||
}
|
||||
|
||||
if (!allTargetTypes.includes(data.target_type)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
|
||||
Reference in New Issue
Block a user