diff --git a/.changeset/eleven-rules-battle.md b/.changeset/eleven-rules-battle.md new file mode 100644 index 0000000000000..afc4117b29142 --- /dev/null +++ b/.changeset/eleven-rules-battle.md @@ -0,0 +1,6 @@ +--- +"@medusajs/dashboard": patch +"@medusajs/core-flows": patch +--- + +fix(dashboard, core-flows): improvements to order page on canceled orders diff --git a/integration-tests/http/__tests__/order/admin/order.spec.ts b/integration-tests/http/__tests__/order/admin/order.spec.ts index 8e6fb14be7d61..0e548219c03a6 100644 --- a/integration-tests/http/__tests__/order/admin/order.spec.ts +++ b/integration-tests/http/__tests__/order/admin/order.spec.ts @@ -443,11 +443,12 @@ medusaIntegrationTestRunner({ amount: 106, payments: [ expect.objectContaining({ - // canceled_at: expect.any(String), + canceled_at: null, refunds: [ expect.objectContaining({ id: expect.any(String), amount: 106, + created_by: expect.any(String), }), ], captures: [ @@ -488,11 +489,9 @@ medusaIntegrationTestRunner({ }) ) - const response = await api.post( - `/admin/orders/${order.id}/cancel`, - {}, - adminHeaders - ) + const response = await api + .post(`/admin/orders/${order.id}/cancel`, {}, adminHeaders) + .catch((e) => e) expect(response.status).toBe(200) expect(response.data.order).toEqual( @@ -514,11 +513,11 @@ medusaIntegrationTestRunner({ amount: 106, payments: [ expect.objectContaining({ - // canceled_at: expect.any(String), refunds: [ expect.objectContaining({ id: expect.any(String), amount: 50, + created_by: expect.any(String), }), ], captures: [ diff --git a/packages/admin/dashboard/src/routes/orders/order-create-refund/components/create-refund-form/create-refund-form.tsx b/packages/admin/dashboard/src/routes/orders/order-create-refund/components/create-refund-form/create-refund-form.tsx index ec38aae71c290..c9121b33bfbb4 100644 --- a/packages/admin/dashboard/src/routes/orders/order-create-refund/components/create-refund-form/create-refund-form.tsx +++ b/packages/admin/dashboard/src/routes/orders/order-create-refund/components/create-refund-form/create-refund-form.tsx @@ -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>({ defaultValues: { amount: paymentAmount, @@ -121,19 +120,32 @@ export const CreateRefundForm = ({ - {payments.map((payment) => ( - - - {getLocaleAmount( - payment.amount as number, - payment.currency_code - )} - {" - "} - - {payment.provider_id} - - ({payment.id.replace("pay_", "")}) - - ))} + {payments.map((payment) => { + const totalRefunded = payment.refunds.reduce( + (acc, next) => next.amount + acc, + 0 + ) + + return ( + = payment.amount + } + > + + {getLocaleAmount( + payment.amount as number, + payment.currency_code + )} + {" - "} + + {payment.provider_id} + - ({payment.id.replace("pay_", "")}) + + ) + })} @@ -154,16 +166,11 @@ export const CreateRefundForm = ({ { - 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)} diff --git a/packages/admin/dashboard/src/routes/orders/order-detail/components/order-fulfillment-section/order-fulfillment-section.tsx b/packages/admin/dashboard/src/routes/orders/order-detail/components/order-fulfillment-section/order-fulfillment-section.tsx index c4adb2e494e4d..69e521a58e52b 100644 --- a/packages/admin/dashboard/src/routes/orders/order-detail/components/order-fulfillment-section/order-fulfillment-section.tsx +++ b/packages/admin/dashboard/src/routes/orders/order-detail/components/order-fulfillment-section/order-fulfillment-section.tsx @@ -150,6 +150,10 @@ const UnfulfilledItemDisplay = ({ }) => { const { t } = useTranslation() + if (order.status === "canceled") { + return + } + return (
diff --git a/packages/admin/dashboard/src/routes/orders/order-detail/components/order-payment-section/order-payment-section.tsx b/packages/admin/dashboard/src/routes/orders/order-detail/components/order-payment-section/order-payment-section.tsx index b9324ef7c94f4..796ad8ce0cd8b 100644 --- a/packages/admin/dashboard/src/routes/orders/order-detail/components/order-payment-section/order-payment-section.tsx +++ b/packages/admin/dashboard/src/routes/orders/order-detail/components/order-payment-section/order-payment-section.tsx @@ -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} /> - + ) } @@ -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 (
@@ -237,7 +235,10 @@ const Payment = ({ label: t("orders.payment.refund"), icon: , 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 (
@@ -360,20 +355,20 @@ const Total = ({ {getStylizedAmount( - getTotalCaptured(paymentCollections), - currencyCode + getTotalCaptured(order.payment_collections), + order.currency_code )}
- {totalPending > 0 && ( + {order.status !== "canceled" && totalPending > 0 && (
Total pending - {getStylizedAmount(totalPending, currencyCode)} + {getStylizedAmount(totalPending, order.currency_code)}
)} diff --git a/packages/admin/dashboard/src/routes/orders/order-detail/components/order-summary-section/order-summary-section.tsx b/packages/admin/dashboard/src/routes/orders/order-detail/components/order-summary-section/order-summary-section.tsx index c48a14611fbc0..64c69dfb9b784 100644 --- a/packages/admin/dashboard/src/routes/orders/order-detail/components/order-summary-section/order-summary-section.tsx +++ b/packages/admin/dashboard/src/routes/orders/order-detail/components/order-summary-section/order-summary-section.tsx @@ -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: , disabled: + order.status === "canceled" || (orderPreview?.order_change && orderPreview?.order_change?.change_type !== "edit") || (orderPreview?.order_change?.change_type === "edit" && diff --git a/packages/core/core-flows/src/order/workflows/cancel-order.ts b/packages/core/core-flows/src/order/workflows/cancel-order.ts index 6be68ded8bacf..72c24ff105b20 100644 --- a/packages/core/core-flows/src/order/workflows/cancel-order.ts +++ b/packages/core/core-flows/src/order/workflows/cancel-order.ts @@ -140,9 +140,8 @@ export const cancelOrderWorkflow = createWorkflow( deleteReservationsByLineItemsStep(lineItemIds), cancelPaymentStep({ paymentIds: uncapturedPaymentIds }), refundCapturedPaymentsWorkflow.runAsStep({ - input: { order_id: order.id }, + input: { order_id: order.id, created_by: input.canceled_by }, }), - cancelOrdersStep({ orderIds: [order.id] }), emitEventStep({ eventName: OrderWorkflowEvents.CANCELED, data: { id: order.id }, @@ -162,6 +161,8 @@ export const cancelOrderWorkflow = createWorkflow( }) }) + cancelOrdersStep({ orderIds: [order.id] }) + const orderCanceled = createHook("orderCanceled", { order, }) diff --git a/packages/core/core-flows/src/order/workflows/payments/create-order-refund-credit-lines.ts b/packages/core/core-flows/src/order/workflows/payments/create-order-refund-credit-lines.ts index e8cbfac9941ca..903301c485dd1 100644 --- a/packages/core/core-flows/src/order/workflows/payments/create-order-refund-credit-lines.ts +++ b/packages/core/core-flows/src/order/workflows/payments/create-order-refund-credit-lines.ts @@ -20,7 +20,7 @@ import { createOrderChangeActionsWorkflow } from "../create-order-change-actions * This step validates that an order refund credit line can be issued */ export const validateOrderRefundCreditLinesStep = createStep( - "begin-order-edit-validation", + "validate-order-refund-credit-lines", async function ({ order }: { order: OrderDTO }) { throwIfOrderIsCancelled({ order }) } diff --git a/packages/medusa/src/api/admin/orders/[id]/cancel/route.ts b/packages/medusa/src/api/admin/orders/[id]/cancel/route.ts index ded7577afa60f..3c94f76a3f005 100644 --- a/packages/medusa/src/api/admin/orders/[id]/cancel/route.ts +++ b/packages/medusa/src/api/admin/orders/[id]/cancel/route.ts @@ -1,13 +1,13 @@ import { cancelOrderWorkflow } from "@medusajs/core-flows" +import { + AuthenticatedMedusaRequest, + MedusaResponse, +} from "@medusajs/framework/http" import { HttpTypes } from "@medusajs/framework/types" import { ContainerRegistrationKeys, remoteQueryObjectFromString, } from "@medusajs/framework/utils" -import { - AuthenticatedMedusaRequest, - MedusaResponse, -} from "@medusajs/framework/http" export const POST = async ( req: AuthenticatedMedusaRequest, @@ -33,5 +33,6 @@ export const POST = async ( }) const [order] = await remoteQuery(queryObject) + res.status(200).json({ order }) }