feat(dashboard,core,modules): free shipping promotion in dashboard (#13263)
* feat(dashboard,core,modules): free shipping promotion in dashboard * self-review * adapt for edit to work * changeset * integration tests * across for each * remove only from tests * remove console log * revert to across * update wording for shipping promotions * modify changeset * suggestion frane * fix i18n schema
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
---
|
||||
"@medusajs/link-modules": patch
|
||||
"@medusajs/promotion": patch
|
||||
"@medusajs/dashboard": patch
|
||||
"@medusajs/core-flows": patch
|
||||
"@medusajs/js-sdk": patch
|
||||
"@medusajs/types": patch
|
||||
---
|
||||
|
||||
feat(dashboard,core-flows,js-sdk,link-modules,promotion): free shipping promotion in dashboard
|
||||
@@ -21,10 +21,15 @@ export const promotionsQueryKeys = {
|
||||
ruleType: string,
|
||||
query?: HttpTypes.AdminGetPromotionRuleParams
|
||||
) => [PROMOTIONS_QUERY_KEY, id, ruleType, query],
|
||||
listRuleAttributes: (ruleType: string, promotionType?: string) => [
|
||||
listRuleAttributes: (
|
||||
ruleType: string,
|
||||
promotionType?: string,
|
||||
applicationMethodTargetType?: string
|
||||
) => [
|
||||
PROMOTIONS_QUERY_KEY,
|
||||
ruleType,
|
||||
promotionType,
|
||||
applicationMethodTargetType,
|
||||
],
|
||||
listRuleValues: (
|
||||
ruleType: string,
|
||||
@@ -101,6 +106,7 @@ export const usePromotions = (
|
||||
export const usePromotionRuleAttributes = (
|
||||
ruleType: string,
|
||||
promotionType?: string,
|
||||
applicationMethodTargetType?: string,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
HttpTypes.AdminRuleAttributeOptionsListResponse,
|
||||
@@ -112,9 +118,17 @@ export const usePromotionRuleAttributes = (
|
||||
>
|
||||
) => {
|
||||
const { data, ...rest } = useQuery({
|
||||
queryKey: promotionsQueryKeys.listRuleAttributes(ruleType, promotionType),
|
||||
queryKey: promotionsQueryKeys.listRuleAttributes(
|
||||
ruleType,
|
||||
promotionType,
|
||||
applicationMethodTargetType
|
||||
),
|
||||
queryFn: async () =>
|
||||
sdk.admin.promotion.listRuleAttributes(ruleType, promotionType),
|
||||
sdk.admin.promotion.listRuleAttributes(
|
||||
ruleType,
|
||||
promotionType,
|
||||
applicationMethodTargetType
|
||||
),
|
||||
...options,
|
||||
})
|
||||
|
||||
|
||||
@@ -7516,14 +7516,47 @@
|
||||
"target-rules": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
"order": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["title", "description"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
"shipping_methods": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["title", "description"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["title", "description"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["title", "description"],
|
||||
"required": ["order", "shipping_methods", "items"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"buy-rules": {
|
||||
|
||||
@@ -2010,8 +2010,18 @@
|
||||
"description": "Which customer is allowed to use the promotion code? Promotion code can be used by all customers if left untouched."
|
||||
},
|
||||
"target-rules": {
|
||||
"title": "What items will the promotion be applied to?",
|
||||
"description": "The promotion will be applied to items that match the following conditions."
|
||||
"order": {
|
||||
"title": "What items will the promotion be applied to?",
|
||||
"description": "The promotion will be applied to items that match the following conditions."
|
||||
},
|
||||
"shipping_methods": {
|
||||
"title": "What shipping methods will the promotion be applied to?",
|
||||
"description": "The promotion will be applied to shipping methods that match the following conditions."
|
||||
},
|
||||
"items": {
|
||||
"title": "What items will the promotion be applied to?",
|
||||
"description": "The promotion will be applied to items that match the following conditions."
|
||||
}
|
||||
},
|
||||
"buy-rules": {
|
||||
"title": "What needs to be in the cart to unlock the promotion?",
|
||||
|
||||
+7
-1
@@ -28,7 +28,13 @@ export const EditRulesForm = ({
|
||||
const [rulesToRemove, setRulesToRemove] = useState([])
|
||||
|
||||
const form = useForm<EditRulesType>({
|
||||
defaultValues: { rules: [], type: promotion.type },
|
||||
defaultValues: {
|
||||
rules: [],
|
||||
type: promotion.type,
|
||||
application_method: {
|
||||
target_type: promotion.application_method?.target_type,
|
||||
},
|
||||
},
|
||||
resolver: zodResolver(EditRules),
|
||||
})
|
||||
|
||||
|
||||
+3
@@ -24,6 +24,9 @@ export const EditRules = z.object({
|
||||
field_type: z.string().optional(),
|
||||
})
|
||||
),
|
||||
application_method: z.object({
|
||||
target_type: z.enum(["order", "shipping_methods", "items"]),
|
||||
}),
|
||||
})
|
||||
|
||||
export type EditRulesType = z.infer<typeof EditRules>
|
||||
|
||||
+10
-3
@@ -1,9 +1,13 @@
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import {
|
||||
ApplicationMethodTargetTypeValues,
|
||||
HttpTypes,
|
||||
RuleTypeValues,
|
||||
} from "@medusajs/types"
|
||||
import { Input } from "@medusajs/ui"
|
||||
import { useWatch } from "react-hook-form"
|
||||
import { Form } from "../../../../../../components/common/form"
|
||||
import { Combobox } from "../../../../../../components/inputs/combobox"
|
||||
import { useStore } from "../../../../../../hooks/api/store"
|
||||
import { useStore } from "../../../../../../hooks/api"
|
||||
import { useComboboxData } from "../../../../../../hooks/use-combobox-data"
|
||||
import { sdk } from "../../../../../../lib/client"
|
||||
|
||||
@@ -18,7 +22,8 @@ type RuleValueFormFieldType = {
|
||||
operator: string
|
||||
fieldRule: any
|
||||
attributes: HttpTypes.AdminRuleAttributeOption[]
|
||||
ruleType: "rules" | "target-rules" | "buy-rules"
|
||||
ruleType: RuleTypeValues
|
||||
applicationMethodTargetType: ApplicationMethodTargetTypeValues | undefined
|
||||
}
|
||||
|
||||
const buildFilters = (attribute?: string, store?: HttpTypes.AdminStore) => {
|
||||
@@ -44,6 +49,7 @@ export const RuleValueFormField = ({
|
||||
fieldRule,
|
||||
attributes,
|
||||
ruleType,
|
||||
applicationMethodTargetType,
|
||||
}: RuleValueFormFieldType) => {
|
||||
const attribute = attributes?.find(
|
||||
(attr) => attr.value === fieldRule.attribute
|
||||
@@ -59,6 +65,7 @@ export const RuleValueFormField = ({
|
||||
{
|
||||
...params,
|
||||
...buildFilters(attribute?.id, store!),
|
||||
application_method_target_type: applicationMethodTargetType,
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
+23
-3
@@ -41,7 +41,11 @@ export const RulesFormField = ({
|
||||
}: RulesFormFieldType) => {
|
||||
const { t } = useTranslation()
|
||||
const formData = form.getValues()
|
||||
const { attributes } = usePromotionRuleAttributes(ruleType, formData.type)
|
||||
const { attributes } = usePromotionRuleAttributes(
|
||||
ruleType,
|
||||
formData.type,
|
||||
formData.application_method?.target_type
|
||||
)
|
||||
|
||||
const { fields, append, remove, update, replace } = useFieldArray({
|
||||
control: form.control,
|
||||
@@ -61,10 +65,17 @@ export const RulesFormField = ({
|
||||
defaultValue: promotion?.application_method?.type,
|
||||
})
|
||||
|
||||
const applicationMethodTargetType = useWatch({
|
||||
control: form.control,
|
||||
name: "application_method.target_type",
|
||||
defaultValue: promotion?.application_method?.target_type,
|
||||
})
|
||||
|
||||
const query: Record<string, string> = promotionType
|
||||
? {
|
||||
promotion_type: promotionType,
|
||||
application_method_type: applicationMethodType,
|
||||
application_method_target_type: applicationMethodTargetType,
|
||||
}
|
||||
: {}
|
||||
|
||||
@@ -121,11 +132,19 @@ export const RulesFormField = ({
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<Heading level="h2" className="mb-2">
|
||||
{t(`promotions.fields.conditions.${ruleType}.title`)}
|
||||
{t(
|
||||
ruleType === "target-rules"
|
||||
? `promotions.fields.conditions.${ruleType}.${applicationMethodTargetType}.title`
|
||||
: `promotions.fields.conditions.${ruleType}.title`
|
||||
)}
|
||||
</Heading>
|
||||
|
||||
<Text className="text-ui-fg-subtle txt-small mb-6">
|
||||
{t(`promotions.fields.conditions.${ruleType}.description`)}
|
||||
{t(
|
||||
ruleType === "target-rules"
|
||||
? `promotions.fields.conditions.${ruleType}.${applicationMethodTargetType}.description`
|
||||
: `promotions.fields.conditions.${ruleType}.description`
|
||||
)}
|
||||
</Text>
|
||||
|
||||
{fields.map((fieldRule, index) => {
|
||||
@@ -307,6 +326,7 @@ export const RulesFormField = ({
|
||||
fieldRule={fieldRule}
|
||||
attributes={attributes}
|
||||
ruleType={ruleType}
|
||||
applicationMethodTargetType={applicationMethodTargetType}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+90
-87
@@ -678,60 +678,62 @@ export const CreatePromotionForm = () => {
|
||||
|
||||
<RulesFormField form={form} ruleType={"rules"} />
|
||||
|
||||
<Divider />
|
||||
|
||||
{!currentTemplate?.hiddenFields?.includes(
|
||||
"application_method.type"
|
||||
) && (
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="application_method.type"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("promotions.fields.value_type")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup
|
||||
className="flex gap-y-3"
|
||||
{...field}
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"fixed"}
|
||||
label={t(
|
||||
"promotions.form.value_type.fixed.title"
|
||||
)}
|
||||
description={t(
|
||||
"promotions.form.value_type.fixed.description"
|
||||
)}
|
||||
className={clx("basis-1/2")}
|
||||
/>
|
||||
<>
|
||||
<Divider />
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="application_method.type"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("promotions.fields.value_type")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup
|
||||
className="flex gap-y-3"
|
||||
{...field}
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"fixed"}
|
||||
label={t(
|
||||
"promotions.form.value_type.fixed.title"
|
||||
)}
|
||||
description={t(
|
||||
"promotions.form.value_type.fixed.description"
|
||||
)}
|
||||
className={clx("basis-1/2")}
|
||||
/>
|
||||
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"percentage"}
|
||||
label={t(
|
||||
"promotions.form.value_type.percentage.title"
|
||||
)}
|
||||
description={t(
|
||||
"promotions.form.value_type.percentage.description"
|
||||
)}
|
||||
className={clx("basis-1/2")}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"percentage"}
|
||||
label={t(
|
||||
"promotions.form.value_type.percentage.title"
|
||||
)}
|
||||
description={t(
|
||||
"promotions.form.value_type.percentage.description"
|
||||
)}
|
||||
className={clx("basis-1/2")}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="flex gap-x-2 gap-y-4">
|
||||
{!currentTemplate?.hiddenFields?.includes(
|
||||
"application_method.value"
|
||||
) && (
|
||||
{!currentTemplate?.hiddenFields?.includes(
|
||||
"application_method.value"
|
||||
) && (
|
||||
<>
|
||||
<Divider />
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="application_method.value"
|
||||
@@ -806,48 +808,48 @@ export const CreatePromotionForm = () => {
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{isTypeStandard && watchAllocation === "each" && (
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="application_method.max_quantity"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item className="basis-1/2">
|
||||
<Form.Label>
|
||||
{t("promotions.form.max_quantity.title")}
|
||||
</Form.Label>
|
||||
{isTypeStandard && watchAllocation === "each" && (
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="application_method.max_quantity"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item className="basis-1/2">
|
||||
<Form.Label>
|
||||
{t("promotions.form.max_quantity.title")}
|
||||
</Form.Label>
|
||||
|
||||
<Form.Control>
|
||||
<Input
|
||||
{...form.register(
|
||||
"application_method.max_quantity",
|
||||
{ valueAsNumber: true }
|
||||
)}
|
||||
type="number"
|
||||
min={1}
|
||||
placeholder="3"
|
||||
/>
|
||||
</Form.Control>
|
||||
<Form.Control>
|
||||
<Input
|
||||
{...form.register(
|
||||
"application_method.max_quantity",
|
||||
{ valueAsNumber: true }
|
||||
)}
|
||||
type="number"
|
||||
min={1}
|
||||
placeholder="3"
|
||||
/>
|
||||
</Form.Control>
|
||||
|
||||
<Text
|
||||
size="small"
|
||||
leading="compact"
|
||||
className="text-ui-fg-subtle"
|
||||
>
|
||||
<Trans
|
||||
t={t}
|
||||
i18nKey="promotions.form.max_quantity.description"
|
||||
components={[<br key="break" />]}
|
||||
/>
|
||||
</Text>
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Text
|
||||
size="small"
|
||||
leading="compact"
|
||||
className="text-ui-fg-subtle"
|
||||
>
|
||||
<Trans
|
||||
t={t}
|
||||
i18nKey="promotions.form.max_quantity.description"
|
||||
components={[<br key="break" />]}
|
||||
/>
|
||||
</Text>
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isTypeStandard &&
|
||||
!currentTemplate?.hiddenFields?.includes(
|
||||
@@ -901,6 +903,7 @@ export const CreatePromotionForm = () => {
|
||||
|
||||
{!isTypeStandard && (
|
||||
<>
|
||||
<Divider />
|
||||
<RulesFormField
|
||||
form={form}
|
||||
ruleType={"buy-rules"}
|
||||
|
||||
+23
@@ -22,6 +22,12 @@ const buyGetHiddenFields = [
|
||||
"is_tax_inclusive",
|
||||
]
|
||||
|
||||
const freeShippingHiddenFields = [
|
||||
...commonHiddenFields,
|
||||
"application_method.value",
|
||||
"is_tax_inclusive",
|
||||
]
|
||||
|
||||
export const templates = [
|
||||
{
|
||||
id: "amount_off_products",
|
||||
@@ -104,4 +110,21 @@ export const templates = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "shipping_discount",
|
||||
type: "standard",
|
||||
title: "Free shipping",
|
||||
description: "Applies a 100% discount to shipping fees",
|
||||
hiddenFields: freeShippingHiddenFields,
|
||||
defaults: {
|
||||
is_automatic: "false",
|
||||
type: "standard",
|
||||
application_method: {
|
||||
allocation: "across",
|
||||
target_type: "shipping_methods",
|
||||
type: "percentage",
|
||||
value: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
+8
-2
@@ -1,5 +1,5 @@
|
||||
import { PencilSquare } from "@medusajs/icons"
|
||||
import { HttpTypes, PromotionRuleTypes } from "@medusajs/types"
|
||||
import { ApplicationMethodTargetTypeValues, HttpTypes, PromotionRuleTypes, } from "@medusajs/types"
|
||||
import { Badge, Container, Heading } from "@medusajs/ui"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
@@ -44,11 +44,13 @@ function RuleBlock({ rule }: RuleProps) {
|
||||
type PromotionConditionsSectionProps = {
|
||||
rules: HttpTypes.AdminPromotionRule[]
|
||||
ruleType: PromotionRuleTypes
|
||||
applicationMethodTargetType: ApplicationMethodTargetTypeValues
|
||||
}
|
||||
|
||||
export const PromotionConditionsSection = ({
|
||||
rules,
|
||||
ruleType,
|
||||
applicationMethodTargetType,
|
||||
}: PromotionConditionsSectionProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@@ -57,7 +59,11 @@ export const PromotionConditionsSection = ({
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
<div className="flex flex-col">
|
||||
<Heading>
|
||||
{t(`promotions.fields.conditions.${ruleType}.title`)}
|
||||
{t(
|
||||
ruleType === "target-rules"
|
||||
? `promotions.fields.conditions.${ruleType}.${applicationMethodTargetType}.title`
|
||||
: `promotions.fields.conditions.${ruleType}.title`
|
||||
)}
|
||||
</Heading>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -52,11 +52,15 @@ export const PromotionDetail = () => {
|
||||
<PromotionConditionsSection
|
||||
rules={targetRules || []}
|
||||
ruleType={"target-rules"}
|
||||
applicationMethodTargetType={
|
||||
promotion.application_method.target_type || "items"
|
||||
}
|
||||
/>
|
||||
{promotion.type === "buyget" && (
|
||||
<PromotionConditionsSection
|
||||
rules={buyRules || []}
|
||||
ruleType={"buy-rules"}
|
||||
applicationMethodTargetType={"items"}
|
||||
/>
|
||||
)}
|
||||
</TwoColumnPage.Main>
|
||||
|
||||
+132
-126
@@ -1,13 +1,6 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { AdminPromotion } from "@medusajs/types"
|
||||
import {
|
||||
Button,
|
||||
CurrencyInput,
|
||||
Input,
|
||||
RadioGroup,
|
||||
Switch,
|
||||
Text,
|
||||
} from "@medusajs/ui"
|
||||
import { Button, CurrencyInput, Input, RadioGroup, Text } from "@medusajs/ui"
|
||||
import { useForm, useWatch } from "react-hook-form"
|
||||
import { Trans, useTranslation } from "react-i18next"
|
||||
import { useEffect } from "react"
|
||||
@@ -33,6 +26,7 @@ const EditPromotionSchema = zod.object({
|
||||
value_type: zod.enum(["fixed", "percentage"]),
|
||||
value: zod.number(),
|
||||
allocation: zod.enum(["each", "across"]),
|
||||
target_type: zod.enum(["order", "shipping_methods", "items"]),
|
||||
})
|
||||
|
||||
export const EditPromotionDetailsForm = ({
|
||||
@@ -50,6 +44,7 @@ export const EditPromotionDetailsForm = ({
|
||||
value: promotion.application_method!.value,
|
||||
allocation: promotion.application_method!.allocation,
|
||||
value_type: promotion.application_method!.type,
|
||||
target_type: promotion.application_method!.target_type,
|
||||
},
|
||||
resolver: zodResolver(EditPromotionSchema),
|
||||
})
|
||||
@@ -223,128 +218,139 @@ export const EditPromotionDetailsForm = ({
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="value_type"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>{t("promotions.fields.value_type")}</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup
|
||||
className="flex-col gap-y-3"
|
||||
{...field}
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"fixed"}
|
||||
label={t("promotions.form.value_type.fixed.title")}
|
||||
description={t(
|
||||
"promotions.form.value_type.fixed.description"
|
||||
)}
|
||||
/>
|
||||
{promotion.application_method?.target_type !==
|
||||
"shipping_methods" && (
|
||||
<>
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="value_type"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("promotions.fields.value_type")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup
|
||||
className="flex-col gap-y-3"
|
||||
{...field}
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"fixed"}
|
||||
label={t(
|
||||
"promotions.form.value_type.fixed.title"
|
||||
)}
|
||||
description={t(
|
||||
"promotions.form.value_type.fixed.description"
|
||||
)}
|
||||
/>
|
||||
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"percentage"}
|
||||
label={t(
|
||||
"promotions.form.value_type.percentage.title"
|
||||
)}
|
||||
description={t(
|
||||
"promotions.form.value_type.percentage.description"
|
||||
)}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"percentage"}
|
||||
label={t(
|
||||
"promotions.form.value_type.percentage.title"
|
||||
)}
|
||||
description={t(
|
||||
"promotions.form.value_type.percentage.description"
|
||||
)}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="value"
|
||||
render={({ field: { onChange, ...field } }) => {
|
||||
const currencyCode =
|
||||
promotion.application_method?.currency_code ?? "USD"
|
||||
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="value"
|
||||
render={({ field: { onChange, ...field } }) => {
|
||||
const currencyCode =
|
||||
promotion.application_method?.currency_code ?? "USD"
|
||||
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{isFixedValueType
|
||||
? t("fields.amount")
|
||||
: t("fields.percentage")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
{isFixedValueType ? (
|
||||
<CurrencyInput
|
||||
min={0}
|
||||
onValueChange={(val) =>
|
||||
onChange(val ? parseInt(val) : null)
|
||||
}
|
||||
code={currencyCode}
|
||||
symbol={getCurrencySymbol(currencyCode)}
|
||||
{...field}
|
||||
value={field.value}
|
||||
/>
|
||||
) : (
|
||||
<DeprecatedPercentageInput
|
||||
key="amount"
|
||||
min={0}
|
||||
max={100}
|
||||
{...field}
|
||||
value={field.value || ""}
|
||||
onChange={(e) => {
|
||||
onChange(
|
||||
e.target.value === ""
|
||||
? null
|
||||
: parseInt(e.target.value)
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="allocation"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>{t("promotions.fields.allocation")}</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup
|
||||
className="flex-col gap-y-3"
|
||||
{...field}
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"each"}
|
||||
label={t("promotions.form.allocation.each.title")}
|
||||
description={t(
|
||||
"promotions.form.allocation.each.description"
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{isFixedValueType
|
||||
? t("fields.amount")
|
||||
: t("fields.percentage")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
{isFixedValueType ? (
|
||||
<CurrencyInput
|
||||
min={0}
|
||||
onValueChange={(val) =>
|
||||
onChange(val ? parseInt(val) : null)
|
||||
}
|
||||
code={currencyCode}
|
||||
symbol={getCurrencySymbol(currencyCode)}
|
||||
{...field}
|
||||
value={field.value}
|
||||
/>
|
||||
) : (
|
||||
<DeprecatedPercentageInput
|
||||
key="amount"
|
||||
min={0}
|
||||
max={100}
|
||||
{...field}
|
||||
value={field.value || ""}
|
||||
onChange={(e) => {
|
||||
onChange(
|
||||
e.target.value === ""
|
||||
? null
|
||||
: parseInt(e.target.value)
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="allocation"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("promotions.fields.allocation")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<RadioGroup
|
||||
className="flex-col gap-y-3"
|
||||
{...field}
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"each"}
|
||||
label={t("promotions.form.allocation.each.title")}
|
||||
description={t(
|
||||
"promotions.form.allocation.each.description"
|
||||
)}
|
||||
/>
|
||||
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"across"}
|
||||
label={t("promotions.form.allocation.across.title")}
|
||||
description={t(
|
||||
"promotions.form.allocation.across.description"
|
||||
)}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<RadioGroup.ChoiceBox
|
||||
value={"across"}
|
||||
label={t(
|
||||
"promotions.form.allocation.across.title"
|
||||
)}
|
||||
description={t(
|
||||
"promotions.form.allocation.across.description"
|
||||
)}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</RouteDrawer.Body>
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ export const cartFieldsForRefreshSteps = [
|
||||
"shipping_methods.*",
|
||||
"shipping_methods.adjustments.*",
|
||||
"shipping_methods.tax_lines.*",
|
||||
"shipping_methods.shipping_option.shipping_option_type_id",
|
||||
"customer.*",
|
||||
"customer.groups.*",
|
||||
"promotions.id",
|
||||
|
||||
@@ -15,27 +15,27 @@ export class Promotion {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method retrieves a promotion by its ID. It sends a request to the
|
||||
* This method retrieves a promotion by its ID. It sends a request to the
|
||||
* [Retrieve Promotion](https://docs.medusajs.com/api/admin#promotions_getpromotionsid)
|
||||
* API route.
|
||||
*
|
||||
*
|
||||
* @param id - The promotion's ID.
|
||||
* @param query - Configure the fields to retrieve in the promotion.
|
||||
* @param headers - Headers to pass in the request.
|
||||
* @returns The promotion's details.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* To retrieve a promotion by its ID:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* sdk.admin.promotion.retrieve("promo_123")
|
||||
* .then(({ promotion }) => {
|
||||
* console.log(promotion)
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* To specify the fields and relations to retrieve:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* sdk.admin.promotion.retrieve("promo_123", {
|
||||
* fields: "id,*application_method"
|
||||
@@ -44,7 +44,7 @@ export class Promotion {
|
||||
* console.log(promotion)
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* Learn more about the `fields` property in the [API reference](https://docs.medusajs.com/api/admin#select-fields-and-relations).
|
||||
*/
|
||||
async retrieve(
|
||||
@@ -62,28 +62,28 @@ export class Promotion {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method retrieves a list of promotions. It sends a request to the
|
||||
* This method retrieves a list of promotions. It sends a request to the
|
||||
* [List Promotions](https://docs.medusajs.com/api/admin#promotions_getpromotions)
|
||||
* API route.
|
||||
*
|
||||
*
|
||||
* @param query - Filters and pagination configurations.
|
||||
* @param headers - Headers to pass in the request.
|
||||
* @returns The list of promotions.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* To retrieve the list of promotions:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* sdk.admin.promotion.list()
|
||||
* .then(({ promotions, count, limit, offset }) => {
|
||||
* console.log(promotions)
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* To configure the pagination, pass the `limit` and `offset` query parameters.
|
||||
*
|
||||
*
|
||||
* For example, to retrieve only 10 items and skip 10 items:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* sdk.admin.promotion.list({
|
||||
* limit: 10,
|
||||
@@ -93,10 +93,10 @@ export class Promotion {
|
||||
* console.log(promotions)
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* Using the `fields` query parameter, you can specify the fields and relations to retrieve
|
||||
* in each promotion:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* sdk.admin.promotion.list({
|
||||
* fields: "id,*application_method"
|
||||
@@ -105,7 +105,7 @@ export class Promotion {
|
||||
* console.log(promotions)
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* Learn more about the `fields` property in the [API reference](https://docs.medusajs.com/api/admin#select-fields-and-relations).
|
||||
*/
|
||||
async list(
|
||||
@@ -122,16 +122,16 @@ export class Promotion {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a new promotion. It sends a request to the
|
||||
* This method creates a new promotion. It sends a request to the
|
||||
* [Create Promotion](https://docs.medusajs.com/api/admin#promotions_postpromotions)
|
||||
* API route.
|
||||
*
|
||||
*
|
||||
* @param payload - The promotion to create.
|
||||
* @param headers - Headers to pass in the request.
|
||||
* @returns The promotion's details.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* sdk.admin.promotion.create({
|
||||
* sdk.admin.promotion.create({
|
||||
* name: "My Promotion",
|
||||
* description: "This is a test promotion",
|
||||
* code: "PROMO123",
|
||||
@@ -157,15 +157,15 @@ export class Promotion {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method updates a promotion. It sends a request to the
|
||||
* This method updates a promotion. It sends a request to the
|
||||
* [Update Promotion](https://docs.medusajs.com/api/admin#promotions_postpromotionsid)
|
||||
* API route.
|
||||
*
|
||||
*
|
||||
* @param id - The promotion's ID.
|
||||
* @param payload - The details to update in the promotion.
|
||||
* @param headers - Headers to pass in the request.
|
||||
* @returns The promotion's details.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* sdk.admin.promotion.update("promo_123", {
|
||||
* code: "PROMO123",
|
||||
@@ -190,14 +190,14 @@ export class Promotion {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method deletes a promotion. It sends a request to the
|
||||
* This method deletes a promotion. It sends a request to the
|
||||
* [Delete Promotion](https://docs.medusajs.com/api/admin#promotions_deletepromotionsid)
|
||||
* API route.
|
||||
*
|
||||
*
|
||||
* @param id - The promotion's ID.
|
||||
* @param headers - Headers to pass in the request.
|
||||
* @returns The deleted promotion's details.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* sdk.admin.promotion.delete("promo_123")
|
||||
* .then(({ promotion }) => {
|
||||
@@ -218,20 +218,20 @@ export class Promotion {
|
||||
* This method creates and adds rules to a promotion. It can be the promotion's rules,
|
||||
* or its application method's buy or target rules. That depends on the rule type
|
||||
* you specify as a parameter.
|
||||
*
|
||||
* - If you set the `ruleType` to `rules`, the method sends a request to the
|
||||
*
|
||||
* - If you set the `ruleType` to `rules`, the method sends a request to the
|
||||
* [Manage Promotion's Rules API Route](https://docs.medusajs.com/api/admin#promotions_postpromotionsidrulesbatch).
|
||||
* - If you set the `ruleType` to `buy-rules`, the method sends a request to the
|
||||
* - If you set the `ruleType` to `buy-rules`, the method sends a request to the
|
||||
* [Manage Promotion's Buy Rules API Route](https://docs.medusajs.com/api/admin#promotions_postpromotionsidbuyrulesbatch).
|
||||
* - If you set the `ruleType` to `target-rules`, the method sends a request to the
|
||||
* - If you set the `ruleType` to `target-rules`, the method sends a request to the
|
||||
* [Manage Promotion's Target Rules API Route](https://docs.medusajs.com/api/admin#promotions_postpromotionsidtargetrulesbatch).
|
||||
*
|
||||
*
|
||||
* @param id - The promotion's ID.
|
||||
* @param ruleType - The type of rules to create.
|
||||
* @param payload - The rules to create.
|
||||
* @param headers - Headers to pass in the request.
|
||||
* @returns The promotion's details.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* sdk.admin.promotion.addRules("promo_123", "rules", {
|
||||
* rules: [
|
||||
@@ -266,20 +266,20 @@ export class Promotion {
|
||||
* This method updates the rules of a promotion. It can be the promotion's rules,
|
||||
* or its application method's buy or target rules. That depends on the rule type
|
||||
* you specify as a parameter.
|
||||
*
|
||||
* - If you set the `ruleType` to `rules`, the method sends a request to the
|
||||
*
|
||||
* - If you set the `ruleType` to `rules`, the method sends a request to the
|
||||
* [Manage Promotion's Rules API Route](https://docs.medusajs.com/api/admin#promotions_postpromotionsidrulesbatch).
|
||||
* - If you set the `ruleType` to `buy-rules`, the method sends a request to the
|
||||
* - If you set the `ruleType` to `buy-rules`, the method sends a request to the
|
||||
* [Manage Promotion's Buy Rules API Route](https://docs.medusajs.com/api/admin#promotions_postpromotionsidbuyrulesbatch).
|
||||
* - If you set the `ruleType` to `target-rules`, the method sends a request to the
|
||||
* - If you set the `ruleType` to `target-rules`, the method sends a request to the
|
||||
* [Manage Promotion's Target Rules API Route](https://docs.medusajs.com/api/admin#promotions_postpromotionsidtargetrulesbatch).
|
||||
*
|
||||
*
|
||||
* @param id - The promotion's ID.
|
||||
* @param ruleType - The type of rules to update.
|
||||
* @param payload - The rules to update.
|
||||
* @param headers - Headers to pass in the request.
|
||||
* @returns The promotion's details.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* sdk.admin.promotion.updateRules("promo_123", "rules", {
|
||||
* rules: [
|
||||
@@ -313,20 +313,20 @@ export class Promotion {
|
||||
* This method removes rules from a promotion. It can be the promotion's rules,
|
||||
* or its application method's buy or target rules. That depends on the rule type
|
||||
* you specify as a parameter.
|
||||
*
|
||||
* - If you set the `ruleType` to `rules`, the method sends a request to the
|
||||
*
|
||||
* - If you set the `ruleType` to `rules`, the method sends a request to the
|
||||
* [Manage Promotion's Rules API Route](https://docs.medusajs.com/api/admin#promotions_postpromotionsidrulesbatch).
|
||||
* - If you set the `ruleType` to `buy-rules`, the method sends a request to the
|
||||
* - If you set the `ruleType` to `buy-rules`, the method sends a request to the
|
||||
* [Manage Promotion's Buy Rules API Route](https://docs.medusajs.com/api/admin#promotions_postpromotionsidbuyrulesbatch).
|
||||
* - If you set the `ruleType` to `target-rules`, the method sends a request to the
|
||||
* - If you set the `ruleType` to `target-rules`, the method sends a request to the
|
||||
* [Manage Promotion's Target Rules API Route](https://docs.medusajs.com/api/admin#promotions_postpromotionsidtargetrulesbatch).
|
||||
*
|
||||
*
|
||||
* @param id - The promotion's ID.
|
||||
* @param ruleType - The type of rules to remove.
|
||||
* @param payload - The rules to remove.
|
||||
* @param headers - Headers to pass in the request.
|
||||
* @returns The promotion's details.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* sdk.admin.promotion.removeRules("promo_123", "rules", {
|
||||
* rule_ids: ["rule_123"]
|
||||
@@ -355,16 +355,16 @@ export class Promotion {
|
||||
* This method retrieves the rules of a promotion. It can be the promotion's rules,
|
||||
* or its application method's buy or target rules. That depends on the rule type
|
||||
* you specify as a parameter.
|
||||
*
|
||||
*
|
||||
* This method sends a request to the
|
||||
* [List Rules of a Promotion API Route](https://docs.medusajs.com/api/admin#promotions_getpromotionsidrule_type)
|
||||
*
|
||||
*
|
||||
* @param id - The promotion's ID.
|
||||
* @param ruleType - The type of rules to retrieve. Can be `rules`, `buy-rules`, or `target-rules`.
|
||||
* @param query - Configure the fields to retrieve in the rules.
|
||||
* @param headers - Headers to pass in the request.
|
||||
* @returns The promotion's rules.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* sdk.admin.promotion.listRules("promo_123", "rules")
|
||||
* .then(({ rules }) => {
|
||||
@@ -389,19 +389,20 @@ export class Promotion {
|
||||
|
||||
/**
|
||||
* Retrieve a list of potential rule attributes for the promotion and application method types specified in the query parameters. Only the attributes of the rule type specified in the path parameter are retrieved:
|
||||
*
|
||||
*
|
||||
* - If `rule_type` is `rules`, the attributes of the promotion's type are retrieved.
|
||||
* - If `rule_type` is `target-rules`, the target rules' attributes of the application method's type are retrieved.
|
||||
* - If `rule_type` is `buy-rules`, the buy rules' attributes of the application method's type are retrieved.
|
||||
*
|
||||
*
|
||||
* This method sends a request to the
|
||||
* [List Rule Attribute Options API Route](https://docs.medusajs.com/api/admin#promotions_getpromotionsruleattributeoptionsrule_type)
|
||||
*
|
||||
*
|
||||
* @param ruleType - The type of rules to retrieve the attributes for. Can be `rules`, `buy-rules`, or `target-rules`.
|
||||
* @param promotionType - The type of promotion to retrieve the attributes for. It can be `standard` or `buyget`.
|
||||
* @param applicationMethodTargetType - The type of application method to retrieve the attributes for. It can be `order`, `items` or `shipping_methods`.
|
||||
* @param headers - Headers to pass in the request.
|
||||
* @returns The list of rule attributes.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* sdk.admin.promotion.listRuleAttributes("rules", "standard")
|
||||
* .then(({ attributes }) => {
|
||||
@@ -411,6 +412,7 @@ export class Promotion {
|
||||
async listRuleAttributes(
|
||||
ruleType: string,
|
||||
promotionType?: string,
|
||||
applicationMethodTargetType?: string,
|
||||
headers?: ClientHeaders
|
||||
) {
|
||||
// eslint-disable-next-line max-len
|
||||
@@ -418,25 +420,28 @@ export class Promotion {
|
||||
`/admin/promotions/rule-attribute-options/${ruleType}`,
|
||||
{
|
||||
headers,
|
||||
query: { promotion_type: promotionType },
|
||||
query: {
|
||||
promotion_type: promotionType,
|
||||
application_method_target_type: applicationMethodTargetType,
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all potential values for promotion rules and target and buy rules based on the specified rule attribute and type.
|
||||
* For example, if you provide the ID of the `currency_code` rule attribute, and set `rule_type` to rules,
|
||||
* Retrieve all potential values for promotion rules and target and buy rules based on the specified rule attribute and type.
|
||||
* For example, if you provide the ID of the `currency_code` rule attribute, and set `rule_type` to rules,
|
||||
* a list of currencies are retrieved in label-value pairs.
|
||||
*
|
||||
*
|
||||
* This method sends a request to the
|
||||
* [List Rule Values API Route](https://docs.medusajs.com/api/admin#promotions_getpromotionsrulevalueoptionsrule_typerule_attribute_id)
|
||||
*
|
||||
*
|
||||
* @param ruleType - The type of rules to retrieve the values for. Can be `rules`, `buy-rules`, or `target-rules`.
|
||||
* @param ruleValue - The ID of the rule attribute to retrieve the values for.
|
||||
* @param query - Configure the fields to retrieve in the rule values.
|
||||
* @param headers - Headers to pass in the request.
|
||||
* @returns The list of rule values.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* sdk.admin.promotion.listRuleValues("rules", "attr_123")
|
||||
* .then(({ values }) => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { BaseFilterable, OperatorMap } from "../../../dal"
|
||||
import {
|
||||
ApplicationMethodTargetTypeValues,
|
||||
ApplicationMethodTypeValues,
|
||||
PromotionTypeValues,
|
||||
} from "../../../promotion"
|
||||
@@ -64,6 +65,7 @@ export interface AdminGetPromotionsParams
|
||||
export interface AdminGetPromotionRuleParams {
|
||||
promotion_type?: PromotionTypeValues
|
||||
application_method_type?: ApplicationMethodTypeValues
|
||||
application_method_target_type?: ApplicationMethodTargetTypeValues
|
||||
}
|
||||
|
||||
export interface AdminGetPromotionRuleTypeParams extends SelectParams {
|
||||
@@ -80,4 +82,5 @@ export interface AdminGetPromotionsRuleValueParams extends FindParams {
|
||||
* Filter by rule value.
|
||||
*/
|
||||
value?: string | string[]
|
||||
application_method_target_type?: ApplicationMethodTargetTypeValues
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { ModuleJoinerConfig } from "@medusajs/framework/types"
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
|
||||
export const CartShippingOption: ModuleJoinerConfig = {
|
||||
isLink: true,
|
||||
isReadOnlyLink: true,
|
||||
extends: [
|
||||
{
|
||||
serviceName: Modules.CART,
|
||||
entity: "ShippingMethod",
|
||||
relationship: {
|
||||
serviceName: Modules.FULFILLMENT,
|
||||
primaryKey: "id",
|
||||
foreignKey: "shipping_option_id",
|
||||
alias: "shipping_option",
|
||||
args: {
|
||||
methodSuffix: "ShippingOptions",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -2,6 +2,7 @@ export * from "./cart-customer"
|
||||
export * from "./cart-product"
|
||||
export * from "./cart-region"
|
||||
export * from "./cart-sales-channel"
|
||||
export * from "./cart-shipping-option"
|
||||
export * from "./inventory-level-stock-location"
|
||||
export * from "./line-item-adjustment-promotion"
|
||||
export * from "./order-customer"
|
||||
|
||||
+1
-6
@@ -1,10 +1,5 @@
|
||||
import { IPromotionModuleService } from "@medusajs/framework/types"
|
||||
import {
|
||||
ApplicationMethodType,
|
||||
Modules,
|
||||
PromotionStatus,
|
||||
PromotionType,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { ApplicationMethodType, Modules, PromotionStatus, PromotionType, } from "@medusajs/framework/utils"
|
||||
import { moduleIntegrationTestRunner, SuiteOptions } from "@medusajs/test-utils"
|
||||
import { createCampaigns } from "../../../__fixtures__/campaigns"
|
||||
import { createDefaultPromotion } from "../../../__fixtures__/promotion"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./buy-get"
|
||||
export * from "./line-items"
|
||||
export * from "./shipping-methods"
|
||||
export * from "./usage"
|
||||
|
||||
@@ -6,11 +6,11 @@ import {
|
||||
import {
|
||||
ApplicationMethodAllocation,
|
||||
ApplicationMethodTargetType,
|
||||
ApplicationMethodTargetType as TargetType,
|
||||
calculateAdjustmentAmountFromPromotion,
|
||||
ComputedActions,
|
||||
MathBN,
|
||||
MedusaError,
|
||||
ApplicationMethodTargetType as TargetType,
|
||||
calculateAdjustmentAmountFromPromotion,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { areRulesValidForContext } from "../validations"
|
||||
import { computeActionForBudgetExceeded } from "./usage"
|
||||
@@ -43,29 +43,6 @@ export function getComputedActionsForItems(
|
||||
)
|
||||
}
|
||||
|
||||
export function getComputedActionsForShippingMethods(
|
||||
promotion: PromotionTypes.PromotionDTO,
|
||||
shippingMethods: PromotionTypes.ComputeActionContext[TargetType.SHIPPING_METHODS],
|
||||
appliedPromotionsMap: Map<string, number>
|
||||
): PromotionTypes.ComputeActions[] {
|
||||
validateContext("shipping_methods", shippingMethods)
|
||||
|
||||
return applyPromotionToItems(promotion, shippingMethods, appliedPromotionsMap)
|
||||
}
|
||||
|
||||
export function getComputedActionsForOrder(
|
||||
promotion: PromotionTypes.PromotionDTO,
|
||||
itemApplicationContext: PromotionTypes.ComputeActionContext,
|
||||
methodIdPromoValueMap: Map<string, number>
|
||||
): PromotionTypes.ComputeActions[] {
|
||||
return getComputedActionsForItems(
|
||||
promotion,
|
||||
itemApplicationContext[TargetType.ITEMS],
|
||||
methodIdPromoValueMap,
|
||||
ApplicationMethodAllocation.ACROSS
|
||||
)
|
||||
}
|
||||
|
||||
function applyPromotionToItems(
|
||||
promotion: PromotionTypes.PromotionDTO,
|
||||
items:
|
||||
|
||||
@@ -123,20 +123,13 @@ export function applyPromotionToShippingMethods(
|
||||
}
|
||||
|
||||
const promotionValue = applicationMethod?.value ?? 0
|
||||
const applicableTotal = method.subtotal
|
||||
const appliedPromoValue = methodIdPromoValueMap.get(method.id) ?? 0
|
||||
const applicableTotal = MathBN.sub(method.subtotal, appliedPromoValue)
|
||||
|
||||
const div = MathBN.eq(totalApplicableValue, 0) ? 1 : totalApplicableValue
|
||||
let applicablePromotionValue = MathBN.sub(
|
||||
MathBN.mult(MathBN.div(applicableTotal, div), promotionValue),
|
||||
appliedPromoValue
|
||||
)
|
||||
let applicablePromotionValue = MathBN.mult(MathBN.div(applicableTotal, totalApplicableValue), promotionValue)
|
||||
|
||||
if (applicationMethod?.type === ApplicationMethodType.PERCENTAGE) {
|
||||
applicablePromotionValue = MathBN.sub(
|
||||
MathBN.mult(MathBN.div(promotionValue, 100), applicableTotal),
|
||||
appliedPromoValue
|
||||
)
|
||||
applicablePromotionValue = MathBN.mult(MathBN.div(promotionValue, 100), applicableTotal)
|
||||
}
|
||||
|
||||
const amount = MathBN.min(applicablePromotionValue, applicableTotal)
|
||||
|
||||
Reference in New Issue
Block a user