feat(core-flows): support ad hoc returns (#13598)
* feat(core-flows): support ad hoc returns * fix: missing transform * handle edge case * refactor * replace gte for gt * cleanup * weird bug fix * add test * Create quick-nails-kick.md * stop sending empty strings * add code to refund reason * fix build * fix tests * handle code in dashboard * fix tests * more tests failing * add reference and reference id to credit lieng * rework create refund form
This commit is contained in:
@@ -18,6 +18,13 @@ export const useRefundReasonTableColumns = () => {
|
||||
sortAscLabel: t("filters.sorting.alphabeticallyAsc"),
|
||||
sortDescLabel: t("filters.sorting.alphabeticallyDesc"),
|
||||
}),
|
||||
columnHelper.accessor("code", {
|
||||
header: () => t("fields.code"),
|
||||
enableSorting: true,
|
||||
sortLabel: t("fields.code"),
|
||||
sortAscLabel: t("filters.sorting.alphabeticallyAsc"),
|
||||
sortDescLabel: t("filters.sorting.alphabeticallyDesc"),
|
||||
}),
|
||||
columnHelper.accessor("description", {
|
||||
header: () => t("fields.description"),
|
||||
cell: ({ getValue }) => <DescriptionCell description={getValue()} />,
|
||||
|
||||
@@ -10306,6 +10306,19 @@
|
||||
"required": ["label", "placeholder"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"code": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"placeholder": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["label", "placeholder"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"description": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -10320,7 +10333,7 @@
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["label", "description"],
|
||||
"required": ["label", "code", "description"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2771,6 +2771,10 @@
|
||||
"label": "Label",
|
||||
"placeholder": "Gesture of goodwill"
|
||||
},
|
||||
"code": {
|
||||
"label": "Code",
|
||||
"placeholder": "gesture_of_goodwill"
|
||||
},
|
||||
"description": {
|
||||
"label": "Description",
|
||||
"placeholder": "Customer had a bad shopping experience"
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import {
|
||||
Button,
|
||||
CurrencyInput,
|
||||
Label,
|
||||
Select,
|
||||
Textarea,
|
||||
toast,
|
||||
} from "@medusajs/ui"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { Button, CurrencyInput, Select, Textarea, toast } from "@medusajs/ui"
|
||||
import { useMemo, useState } from "react"
|
||||
import { formatValue } from "react-currency-input-field"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { useTranslation } from "react-i18next"
|
||||
@@ -20,7 +13,6 @@ import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
|
||||
import { useRefundPayment, useRefundReasons } from "../../../../../hooks/api"
|
||||
import { currencies } from "../../../../../lib/data/currencies"
|
||||
import { formatCurrency } from "../../../../../lib/format-currency"
|
||||
import { formatProvider } from "../../../../../lib/format-provider"
|
||||
import { getLocaleAmount } from "../../../../../lib/money-amount-helpers"
|
||||
import { getPaymentsFromOrder } from "../../../../../lib/orders"
|
||||
import { useDocumentDirection } from "../../../../../hooks/use-document-direction"
|
||||
@@ -63,29 +55,10 @@ export const CreateRefundForm = ({ order }: CreateRefundFormProps) => {
|
||||
value: paymentAmount.toFixed(currency.decimal_digits),
|
||||
float: paymentAmount,
|
||||
},
|
||||
note: "",
|
||||
refund_reason_id: "",
|
||||
},
|
||||
resolver: zodResolver(CreateRefundSchema),
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const pendingDifference = order.summary.pending_difference as number
|
||||
const paymentAmount = (payment?.amount || 0) as number
|
||||
const pendingAmount =
|
||||
pendingDifference < 0
|
||||
? Math.min(Math.abs(pendingDifference), paymentAmount)
|
||||
: paymentAmount
|
||||
|
||||
const normalizedAmount =
|
||||
pendingAmount < 0 ? pendingAmount * -1 : pendingAmount
|
||||
|
||||
form.setValue("amount", {
|
||||
value: normalizedAmount.toFixed(currency.decimal_digits),
|
||||
float: normalizedAmount,
|
||||
})
|
||||
}, [payment?.id || ""])
|
||||
|
||||
const { mutateAsync, isPending } = useRefundPayment(order.id, payment?.id!)
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (data) => {
|
||||
@@ -123,53 +96,16 @@ export const CreateRefundForm = ({ order }: CreateRefundFormProps) => {
|
||||
>
|
||||
<RouteDrawer.Body className="flex-1 overflow-auto">
|
||||
<div className="flex flex-col gap-y-4">
|
||||
<Select
|
||||
dir={direction}
|
||||
value={paymentId}
|
||||
onValueChange={(value) => {
|
||||
setPaymentId(value)
|
||||
}}
|
||||
>
|
||||
<Label className="txt-compact-small mb-[-6px] font-sans font-medium">
|
||||
{t("orders.payment.selectPaymentToRefund")}
|
||||
</Label>
|
||||
|
||||
<Select.Trigger>
|
||||
<Select.Value
|
||||
placeholder={t("orders.payment.selectPaymentToRefund")}
|
||||
/>
|
||||
</Select.Trigger>
|
||||
|
||||
<Select.Content>
|
||||
{payments.map((payment) => {
|
||||
const totalRefunded = payment.refunds.reduce(
|
||||
(acc, next) => next.amount + acc,
|
||||
0
|
||||
)
|
||||
|
||||
return (
|
||||
<Select.Item
|
||||
value={payment!.id}
|
||||
key={payment.id}
|
||||
disabled={
|
||||
!!payment.canceled_at || totalRefunded >= payment.amount
|
||||
}
|
||||
className="flex items-center justify-center"
|
||||
>
|
||||
<span>
|
||||
{getLocaleAmount(
|
||||
payment.amount as number,
|
||||
payment.currency_code
|
||||
)}
|
||||
{" - "}
|
||||
</span>
|
||||
<span>{formatProvider(payment.provider_id)}</span>
|
||||
<span> - (#{payment.id.substring(23)})</span>
|
||||
</Select.Item>
|
||||
)
|
||||
})}
|
||||
</Select.Content>
|
||||
</Select>
|
||||
<div className="flex items-center">
|
||||
<span>
|
||||
{getLocaleAmount(
|
||||
payment.amount as number,
|
||||
payment.currency_code
|
||||
)}
|
||||
</span>
|
||||
<span> - </span>
|
||||
<span>(#{payment.id.substring(23)})</span>
|
||||
</div>
|
||||
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
|
||||
@@ -853,10 +853,6 @@ const DiscountAndTotalBreakdown = ({
|
||||
.split("-")
|
||||
.join(" ")
|
||||
|
||||
const prettyReferenceId = creditLine.reference_id ? (
|
||||
<DisplayId id={creditLine.reference_id} />
|
||||
) : null
|
||||
|
||||
return (
|
||||
<div
|
||||
key={creditLine.id}
|
||||
@@ -899,7 +895,7 @@ const DiscountAndTotalBreakdown = ({
|
||||
leading="compact"
|
||||
className="txt-small text-ui-fg-subtle capitalize"
|
||||
>
|
||||
({prettyReference} {prettyReferenceId})
|
||||
({prettyReference})
|
||||
</Text>
|
||||
</div>
|
||||
<div className="relative flex-1">
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useCreateRefundReason } from "../../../../../hooks/api"
|
||||
|
||||
const RefundReasonCreateSchema = z.object({
|
||||
label: z.string().min(1),
|
||||
code: z.string().min(1),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
|
||||
@@ -23,11 +24,20 @@ export const RefundReasonCreateForm = () => {
|
||||
const form = useForm<z.infer<typeof RefundReasonCreateSchema>>({
|
||||
defaultValues: {
|
||||
label: "",
|
||||
code: "",
|
||||
description: "",
|
||||
},
|
||||
resolver: zodResolver(RefundReasonCreateSchema),
|
||||
})
|
||||
|
||||
const generateCodeFromLabel = (label: string) => {
|
||||
return label
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]/g, "_")
|
||||
.replace(/_+/g, "_")
|
||||
.replace(/^_|_$/g, "")
|
||||
}
|
||||
|
||||
const { mutateAsync, isPending } = useCreateRefundReason()
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (data) => {
|
||||
@@ -81,6 +91,42 @@ export const RefundReasonCreateForm = () => {
|
||||
placeholder={t(
|
||||
"refundReasons.fields.label.placeholder"
|
||||
)}
|
||||
onChange={(e) => {
|
||||
if (
|
||||
!form.getFieldState("code").isTouched ||
|
||||
!form.getValues("code")
|
||||
) {
|
||||
form.setValue(
|
||||
"code",
|
||||
generateCodeFromLabel(e.target.value)
|
||||
)
|
||||
}
|
||||
field.onChange(e)
|
||||
}}
|
||||
/>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="code"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("refundReasons.fields.code.label")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t(
|
||||
"refundReasons.fields.code.placeholder"
|
||||
)}
|
||||
/>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
|
||||
@@ -8,7 +8,7 @@ import { z } from "zod"
|
||||
import { Form } from "../../../../../components/common/form"
|
||||
import { RouteDrawer, useRouteModal } from "../../../../../components/modals"
|
||||
import { KeyboundForm } from "../../../../../components/utilities/keybound-form"
|
||||
import { useUpdateRefundReason } from "../../../../../hooks/api/refund-reasons"
|
||||
import { useUpdateRefundReason } from "../../../../../hooks/api"
|
||||
|
||||
type RefundReasonEditFormProps = {
|
||||
refundReason: HttpTypes.AdminRefundReason
|
||||
@@ -16,6 +16,7 @@ type RefundReasonEditFormProps = {
|
||||
|
||||
const RefundReasonEditSchema = z.object({
|
||||
label: z.string().min(1),
|
||||
code: z.string().min(1),
|
||||
description: z.string().optional(),
|
||||
})
|
||||
|
||||
@@ -28,6 +29,7 @@ export const RefundReasonEditForm = ({
|
||||
const form = useForm<z.infer<typeof RefundReasonEditSchema>>({
|
||||
defaultValues: {
|
||||
label: refundReason.label,
|
||||
code: refundReason.code,
|
||||
description: refundReason.description ?? undefined,
|
||||
},
|
||||
resolver: zodResolver(RefundReasonEditSchema),
|
||||
@@ -78,6 +80,26 @@ export const RefundReasonEditForm = ({
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="code"
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>
|
||||
{t("refundReasons.fields.code.label")}
|
||||
</Form.Label>
|
||||
<Form.Control>
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={t("refundReasons.fields.code.placeholder")}
|
||||
/>
|
||||
</Form.Control>
|
||||
<Form.ErrorMessage />
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="description"
|
||||
|
||||
Reference in New Issue
Block a user