fix(dashboard, core-flows): improvements to order page on canceled orders (#10888)

what:

- Remove pending payment for canceled orders
- Hide unfulfilled items for canceled orders
- Disable non refundable payments from being refunded
- Populate refund created_by
- Disable order edit when canceled
- Fix bug https://github.com/medusajs/medusa/issues/10852

RESOLVES CMRC-842
This commit is contained in:
Riqwan Thamir
2025-01-13 17:51:38 +01:00
committed by GitHub
parent 7232a8a930
commit 1758bfb8d0
9 changed files with 77 additions and 61 deletions

View File

@@ -44,8 +44,7 @@ export const CreateRefundForm = ({
const paymentId = searchParams.get("paymentId")
const payments = getPaymentsFromOrder(order)
const payment = payments.find((p) => p.id === paymentId)!
const paymentAmount = (payment?.amount || 0) as number
const paymentAmount = payment.amount || 0
const form = useForm<zod.infer<typeof CreateRefundSchema>>({
defaultValues: {
amount: paymentAmount,
@@ -121,19 +120,32 @@ export const CreateRefundForm = ({
</Select.Trigger>
<Select.Content>
{payments.map((payment) => (
<Select.Item value={payment!.id} key={payment.id}>
<span>
{getLocaleAmount(
payment.amount as number,
payment.currency_code
)}
{" - "}
</span>
<span>{payment.provider_id}</span>
<span> - ({payment.id.replace("pay_", "")})</span>
</Select.Item>
))}
{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
}
>
<span>
{getLocaleAmount(
payment.amount as number,
payment.currency_code
)}
{" - "}
</span>
<span>{payment.provider_id}</span>
<span> - ({payment.id.replace("pay_", "")})</span>
</Select.Item>
)
})}
</Select.Content>
</Select>
@@ -154,16 +166,11 @@ export const CreateRefundForm = ({
<CurrencyInput
{...field}
min={0}
onChange={(e) => {
const val =
e.target.value === ""
? null
: Number(e.target.value)
onValueChange={(value) => {
const fieldValue = value ? parseInt(value) : ""
onChange(val)
if (val && !isNaN(val)) {
if (val < 0 || val > paymentAmount) {
if (fieldValue && !isNaN(fieldValue)) {
if (fieldValue < 0 || fieldValue > paymentAmount) {
form.setError(`amount`, {
type: "manual",
message: t(
@@ -175,6 +182,8 @@ export const CreateRefundForm = ({
form.clearErrors(`amount`)
}
}
onChange(fieldValue)
}}
code={order.currency_code}
symbol={getCurrencySymbol(order.currency_code)}

View File

@@ -150,6 +150,10 @@ const UnfulfilledItemDisplay = ({
}) => {
const { t } = useTranslation()
if (order.status === "canceled") {
return
}
return (
<Container className="divide-y p-0">
<div className="flex items-center justify-between px-6 py-4">

View File

@@ -1,9 +1,5 @@
import { ArrowDownRightMini, DocumentText, XCircle } from "@medusajs/icons"
import {
AdminPayment,
AdminPaymentCollection,
HttpTypes,
} from "@medusajs/types"
import { AdminOrder, AdminPayment, HttpTypes } from "@medusajs/types"
import {
Badge,
Button,
@@ -58,10 +54,7 @@ export const OrderPaymentSection = ({ order }: OrderPaymentSectionProps) => {
currencyCode={order.currency_code}
/>
<Total
paymentCollections={order.payment_collections}
currencyCode={order.currency_code}
/>
<Total order={order} />
</Container>
)
}
@@ -195,6 +188,11 @@ const Payment = ({
const showCapture =
payment.captured_at === null && payment.canceled_at === null
const totalRefunded = payment.refunds.reduce(
(acc, next) => next.amount + acc,
0
)
return (
<div className="divide-y divide-dashed">
<div className="text-ui-fg-subtle grid grid-cols-[1fr_1fr_1fr_20px] items-center gap-x-4 px-6 py-4 sm:grid-cols-[1fr_1fr_1fr_1fr_20px]">
@@ -237,7 +235,10 @@ const Payment = ({
label: t("orders.payment.refund"),
icon: <XCircle />,
to: `/orders/${order.id}/refund?paymentId=${payment.id}`,
disabled: !payment.captured_at,
disabled:
!payment.captured_at ||
!!payment.canceled_at ||
totalRefunded >= payment.amount,
},
],
},
@@ -341,15 +342,9 @@ const PaymentBreakdown = ({
)
}
const Total = ({
paymentCollections,
currencyCode,
}: {
paymentCollections: AdminPaymentCollection[]
currencyCode: string
}) => {
const Total = ({ order }: { order: AdminOrder }) => {
const { t } = useTranslation()
const totalPending = getTotalPending(paymentCollections)
const totalPending = getTotalPending(order.payment_collections)
return (
<div>
@@ -360,20 +355,20 @@ const Total = ({
<Text size="small" weight="plus" leading="compact">
{getStylizedAmount(
getTotalCaptured(paymentCollections),
currencyCode
getTotalCaptured(order.payment_collections),
order.currency_code
)}
</Text>
</div>
{totalPending > 0 && (
{order.status !== "canceled" && totalPending > 0 && (
<div className="flex items-center justify-between px-6 py-4">
<Text size="small" weight="plus" leading="compact">
Total pending
</Text>
<Text size="small" weight="plus" leading="compact">
{getStylizedAmount(totalPending, currencyCode)}
{getStylizedAmount(totalPending, order.currency_code)}
</Text>
</div>
)}

View File

@@ -20,6 +20,7 @@ import {
AdminOrderPreview,
AdminRegion,
AdminReturn,
AdminPaymentCollection,
} from "@medusajs/types"
import {
Badge,
@@ -36,7 +37,6 @@ import {
} from "@medusajs/ui"
import { AdminReservation } from "@medusajs/types/src/http"
import { AdminPaymentCollection } from "../../../../../../../../core/types/dist/http/payment/admin/entities"
import { ActionMenu } from "../../../../../components/common/action-menu"
import { Thumbnail } from "../../../../../components/common/thumbnail"
import { useClaims } from "../../../../../hooks/api/claims"
@@ -309,6 +309,7 @@ const Header = ({
to: `/orders/${order.id}/edits`,
icon: <PencilSquare />,
disabled:
order.status === "canceled" ||
(orderPreview?.order_change &&
orderPreview?.order_change?.change_type !== "edit") ||
(orderPreview?.order_change?.change_type === "edit" &&