fix(dashboard,promotion): percentage promotions + set currency code on percentage promotions (#13161)

This commit is contained in:
Riqwan Thamir authored and GitHub committed 2025-08-07 13:07:41 +02:00
1 parent 9725bff25d
commit 224eaedf5c
5 files changed
+150 -11

No files matched your search

@@ -2725,6 +2725,7 @@ medusaIntegrationTestRunner({
) )
}) })
describe("With promotions", () => {
it("should only apply promotion on discountable items", async () => { it("should only apply promotion on discountable items", async () => {
const notDiscountableProduct = ( const notDiscountableProduct = (
await api.post( await api.post(
@@ -3450,7 +3451,10 @@ medusaIntegrationTestRunner({
let updated = await api.post( let updated = await api.post(
`/store/carts/${cart.id}`, `/store/carts/${cart.id}`,
{ {
promo_codes: [taxInclPromotion50.code, taxInclPromotion100.code], promo_codes: [
taxInclPromotion50.code,
taxInclPromotion100.code,
],
}, },
storeHeaders storeHeaders
) )
@@ -3733,6 +3737,131 @@ medusaIntegrationTestRunner({
}) })
) )
}) })
describe("Percentage promotions", () => {
it("should apply a percentage promotion to a cart", async () => {
const percentagePromotion = (
await api.post(
`/admin/promotions`,
{
code: "PERCENTAGE_PROMOTION",
type: PromotionType.STANDARD,
status: PromotionStatus.ACTIVE,
is_automatic: false,
application_method: {
type: "percentage",
target_type: "items",
allocation: "each",
value: 100,
max_quantity: 1,
currency_code: "usd",
target_rules: [],
},
},
adminHeaders
)
).data.promotion
cart = (
await api.post(
`/store/carts`,
{
currency_code: "usd",
sales_channel_id: salesChannel.id,
region_id: region.id,
shipping_address: shippingAddressData,
items: [
{ variant_id: product.variants[0].id, quantity: 1 },
],
},
storeHeadersWithCustomer
)
).data.cart
let updated = await api.post(
`/store/carts/${cart.id}`,
{
promo_codes: [percentagePromotion.code],
},
storeHeadersWithCustomer
)
expect(updated.status).toEqual(200)
expect(updated.data.cart).toEqual(
expect.objectContaining({
items: expect.arrayContaining([
expect.objectContaining({
adjustments: expect.arrayContaining([
expect.objectContaining({
code: percentagePromotion.code,
}),
]),
}),
]),
})
)
})
it("should not apply a percentage promotion to a cart if cart currency is not the same as the promotion currency", async () => {
const percentagePromotion = (
await api.post(
`/admin/promotions`,
{
code: "PERCENTAGE_PROMOTION",
type: PromotionType.STANDARD,
status: PromotionStatus.ACTIVE,
is_automatic: false,
application_method: {
type: "percentage",
target_type: "items",
allocation: "each",
value: 100,
max_quantity: 1,
currency_code: "eur",
target_rules: [],
},
},
adminHeaders
)
).data.promotion
cart = (
await api.post(
`/store/carts`,
{
currency_code: "usd",
sales_channel_id: salesChannel.id,
region_id: region.id,
shipping_address: shippingAddressData,
items: [
{ variant_id: product.variants[0].id, quantity: 1 },
],
},
storeHeadersWithCustomer
)
).data.cart
let updated = await api.post(
`/store/carts/${cart.id}`,
{
promo_codes: [percentagePromotion.code],
},
storeHeadersWithCustomer
)
expect(updated.status).toEqual(200)
expect(updated.data.cart).toEqual(
expect.objectContaining({
items: expect.arrayContaining([
expect.objectContaining({
adjustments: [],
}),
]),
})
)
})
})
})
}) })
describe("POST /store/carts/:id/customer", () => { describe("POST /store/carts/:id/customer", () => {
@@ -47,12 +47,10 @@ export const CreateCampaignFormFields = ({ form, fieldScope = "" }) => {
if (isTypeSpend) { if (isTypeSpend) {
form.setValue(`campaign.budget.currency_code`, promotionCurrencyValue) form.setValue(`campaign.budget.currency_code`, promotionCurrencyValue)
} } else {
if (watchValueType === "usage") {
form.setValue(`campaign.budget.currency_code`, null) form.setValue(`campaign.budget.currency_code`, null)
} }
}, [watchValueType]) }, [promotionCurrencyValue, isTypeSpend])
if (promotionCurrencyValue) { if (promotionCurrencyValue) {
const formCampaignBudget = form.getValues().campaign?.budget const formCampaignBudget = form.getValues().campaign?.budget
@@ -128,7 +128,7 @@ export const RulesFormField = ({
{t(`promotions.fields.conditions.${ruleType}.description`)} {t(`promotions.fields.conditions.${ruleType}.description`)}
</Text> </Text>
{fields.map((fieldRule: any, index) => { {fields.map((fieldRule, index) => {
const identifier = fieldRule.id const identifier = fieldRule.id
return ( return (
@@ -157,11 +157,23 @@ export const RulesFormField = ({
(ao) => ao.id === e (ao) => ao.id === e
) )
update(index, { const fieldRuleOverrides: typeof fieldRule = {
...fieldRule, ...fieldRule,
values: [],
disguised: currentAttributeOption?.disguised || false, disguised: currentAttributeOption?.disguised || false,
}) }
if (currentAttributeOption?.operators?.length === 1) {
fieldRuleOverrides.operator =
currentAttributeOption.operators[0].value
}
if (fieldRuleOverrides.operator === "eq") {
fieldRuleOverrides.values = ""
} else {
fieldRuleOverrides.values = []
}
update(index, fieldRuleOverrides)
onChange(e) onChange(e)
} }
@@ -299,7 +299,7 @@ export const CreatePromotionForm = () => {
const formData = form.getValues() const formData = form.getValues()
let campaignQuery: object = {} let campaignQuery: object = {}
if (isFixedValueType && formData.application_method.currency_code) { if (formData.application_method.currency_code) {
campaignQuery = { campaignQuery = {
budget: { currency_code: formData.application_method.currency_code }, budget: { currency_code: formData.application_method.currency_code },
} }
@@ -521,7 +521,7 @@ export default class PromotionModuleService
} }
const isCurrencyCodeValid = const isCurrencyCodeValid =
!isDefined(applicationMethod.currency_code) || !isPresent(applicationMethod.currency_code) ||
applicationContext.currency_code === applicationMethod.currency_code applicationContext.currency_code === applicationMethod.currency_code
const isPromotionApplicable = areRulesValidForContext( const isPromotionApplicable = areRulesValidForContext(