Repository: medusajs/medusa
Pull request #12227: fix(core-flows, link-modules): return fulfillment creation
Author: login: fPolic
Labels: name: type: bug
name: team: medusa
Created: 2025-04-17T16:15:49Z | Merged: 2025-04-22T12:33:46Z

**What**
- fix algo for finding the return shipping method
- fix returns <> fulfillements link
- fix cancel claim flow
- fix cancel exchange flow

---

CLOSES SUP-1425


Diff:
diff --git a/.changeset/smart-zoos-flash.md b/.changeset/smart-zoos-flash.md
new file mode 100644
index 0000000000000..53ce129931701
--- /dev/null
+++ b/.changeset/smart-zoos-flash.md
@@ -0,0 +1,5 @@
+---
+"@medusajs/core-flows": patch
+---
+
+fix(core-flows, link-modules): return fulfillment creation
diff --git a/integration-tests/http/__tests__/claims/claims.spec.ts b/integration-tests/http/__tests__/claims/claims.spec.ts
index 266f1c9b16d04..3246be0980557 100644
--- a/integration-tests/http/__tests__/claims/claims.spec.ts
+++ b/integration-tests/http/__tests__/claims/claims.spec.ts
@@ -762,14 +762,39 @@ medusaIntegrationTestRunner({
         })
 
         it("should go through cancel flow successfully", async () => {
+          // fetch claim to get return id
+          let claim = (
+            await api.get(
+              `/admin/claims/${claimId}?fields=return_id`,
+              adminHeaders
+            )
+          ).data.claim
+
+          // fetch return and fulfillment
+          const return_ = (
+            await api.get(
+              `/admin/returns/${claim.return_id}?fields=fulfillments.id`,
+              adminHeaders
+            )
+          ).data.return
+
+          /**
+           * Claim cannot be canceled unless all fulfillments are not canceled
+           */
+          await api.post(
+            `/admin/fulfillments/${return_.fulfillments[0].id}/cancel`,
+            {},
+            adminHeaders
+          )
+
           await api.post(`/admin/claims/${claimId}/cancel`, {}, adminHeaders)
 
-          const [claim] = (
+          claim = (
             await api.get(
-              `/admin/claims?fields=*claim_items,*additional_items`,
+              `/admin/claims/${claimId}?fields=*claim_items,*additional_items`,
               adminHeaders
             )
-          ).data.claims
+          ).data.claim
 
           expect(claim.canceled_at).toBeDefined()
 
diff --git a/integration-tests/http/__tests__/exchanges/exchanges.spec.ts b/integration-tests/http/__tests__/exchanges/exchanges.spec.ts
index b9d9aa100f947..0e4fbbf1c36fa 100644
--- a/integration-tests/http/__tests__/exchanges/exchanges.spec.ts
+++ b/integration-tests/http/__tests__/exchanges/exchanges.spec.ts
@@ -582,6 +582,23 @@ medusaIntegrationTestRunner({
         expect(result[0].additional_items).toHaveLength(1)
         expect(result[0].canceled_at).toBeNull()
 
+        const return_ = (
+          await api.get(
+            `/admin/returns/${result[0].return_id}?fields=*fulfillments`,
+            adminHeaders
+          )
+        ).data.return
+
+        expect(return_.fulfillments).toHaveLength(1)
+        expect(return_.fulfillments[0].canceled_at).toBeNull()
+
+        // all exchange return fulfillments should be canceled before canceling the exchange
+        await api.post(
+          `/admin/fulfillments/${return_.fulfillments[0].id}/cancel`,
+          {},
+          adminHeaders
+        )
+
         await api.post(
           `/admin/exchanges/${exchangeId}/cancel`,
           {},
diff --git a/integration-tests/http/__tests__/returns/returns.spec.ts b/integration-tests/http/__tests__/returns/returns.spec.ts
index 24896a7eb8f0e..78268058d87dc 100644
--- a/integration-tests/http/__tests__/returns/returns.spec.ts
+++ b/integration-tests/http/__tests__/returns/returns.spec.ts
@@ -724,6 +724,39 @@ medusaIntegrationTestRunner({
           })
         )
 
+        const return_ = (
+          await api.get(
+            `/admin/returns/${returnId}?fields=*fulfillments,*fulfillments.items`,
+            adminHeaders
+          )
+        ).data.return
+
+        // return fulfillment is created for the return
+        expect(return_.fulfillments).toHaveLength(1)
+        expect(return_.fulfillments[0]).toEqual(
+          expect.objectContaining({
+            id: expect.any(String),
+            location_id: location.id,
+            packed_at: null,
+            shipped_at: null,
+            marked_shipped_by: null,
+            delivered_at: null,
+            canceled_at: null,
+            data: {},
+            requires_shipping: true,
+            provider_id: "manual_test-provider",
+            items: expect.arrayContaining([
+              expect.objectContaining({
+                id: expect.any(String),
+                title: "Custom Item 2",
+                line_item_id: item.id,
+                inventory_item_id: null,
+                fulfillment_id: return_.fulfillments[0].id,
+                quantity: 2,
+              }),
+            ]),
+          })
+        )
         expect(result.data.order_preview).toEqual(
           expect.objectContaining({
             id: order.id,
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 8ad3896440b1c..8676815436fcc 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
@@ -64,7 +64,6 @@ type OrderSummarySectionProps = {
 
 export const OrderSummarySection = ({ order }: OrderSummarySectionProps) => {
   const { t } = useTranslation()
-  const navigate = useNavigate()
   const prompt = usePrompt()
 
   const { reservations } = useReservationItems(
diff --git a/packages/core/core-flows/src/fulfillment/steps/create-return-fulfillment.ts b/packages/core/core-flows/src/fulfillment/steps/create-return-fulfillment.ts
index a3d5ff2c38daf..ae1e21ca8cf33 100644
--- a/packages/core/core-flows/src/fulfillment/steps/create-return-fulfillment.ts
+++ b/packages/core/core-flows/src/fulfillment/steps/create-return-fulfillment.ts
@@ -8,7 +8,7 @@ import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
 export const createReturnFulfillmentStepId = "create-return-fulfillment"
 /**
  * This step creates a fulfillment for a return.
- * 
+ *
  * @example
  * const data = createReturnFulfillmentStep({
  *   location_id: "sloc_123",
diff --git a/packages/core/core-flows/src/fulfillment/workflows/create-return-fulfillment.ts b/packages/core/core-flows/src/fulfillment/workflows/create-return-fulfillment.ts
index 1a1bddb246344..ba75380d2055d 100644
--- a/packages/core/core-flows/src/fulfillment/workflows/create-return-fulfillment.ts
+++ b/packages/core/core-flows/src/fulfillment/workflows/create-return-fulfillment.ts
@@ -17,17 +17,17 @@ export const createReturnFulfillmentWorkflowId =
 /**
  * This workflow creates a fulfillment for a return. It's used by other return-related workflows,
  * such as {@link createAndCompleteReturnOrderWorkflow}.
- * 
+ *
  * You can use this workflow within your own customizations or custom workflows, allowing you to
  * create a fulfillment for a return within your custom flows.
- * 
+ *
  * :::note
- * 
+ *
  * You can retrieve an order's details using [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query),
  * or [useQueryGraphStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/useQueryGraphStep).
- * 
+ *
  * :::
- * 
+ *
  * @example
  * const { result } = await createReturnFulfillmentWorkflow(container)
  * .run({
@@ -57,9 +57,9 @@ export const createReturnFulfillmentWorkflowId =
  *     }
  *   }
  * })
- * 
+ *
  * @summary
- * 
+ *
  * Create a fulfillment for a return.
  */
 export const createReturnFulfillmentWorkflow = createWorkflow(
diff --git a/packages/core/core-flows/src/order/workflows/claim/cancel-claim.ts b/packages/core/core-flows/src/order/workflows/claim/cancel-claim.ts
index 50c772bb2736d..1ccdc79af162c 100644
--- a/packages/core/core-flows/src/order/workflows/claim/cancel-claim.ts
+++ b/packages/core/core-flows/src/order/workflows/claim/cancel-claim.ts
@@ -2,6 +2,7 @@ import {
   FulfillmentDTO,
   OrderClaimDTO,
   OrderWorkflow,
+  ReturnDTO,
 } from "@medusajs/framework/types"
 import { MedusaError } from "@medusajs/framework/utils"
 import {
@@ -26,6 +27,10 @@ export type CancelClaimValidateOrderStepInput = {
    * The order claim's details.
    */
   orderClaim: OrderClaimDTO
+  /**
+   * The order claim's return details.
+   */
+  orderReturn: ReturnDTO & { fulfillments: FulfillmentDTO[] }
   /**
    * The cancelation details.
    */
@@ -35,14 +40,14 @@ export type CancelClaimValidateOrderStepInput = {
 /**
  * This step validates that a confirmed claim can be canceled. If the claim is canceled,
  * or the claim's fulfillments are not canceled, the step will throw an error.
- * 
+ *
  * :::note
- * 
+ *
  * You can retrieve an order claim's details using [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query),
  * or [useQueryGraphStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/useQueryGraphStep).
- * 
+ *
  * :::
- * 
+ *
  * @example
  * const data = cancelClaimValidateOrderStep({
  *   orderClaim: {
@@ -56,10 +61,8 @@ export type CancelClaimValidateOrderStepInput = {
  */
 export const cancelClaimValidateOrderStep = createStep(
   "validate-claim",
-  ({
-    orderClaim,
-  }: CancelClaimValidateOrderStepInput) => {
-    const orderClaim_ = orderClaim as OrderClaimDTO & {
+  ({ orderClaim, orderReturn }: CancelClaimValidateOrderStepInput) => {
+    const orderReturn_ = orderReturn as ReturnDTO & {
       fulfillments: FulfillmentDTO[]
     }
 
@@ -78,7 +81,7 @@ export const cancelClaimValidateOrderStep = createStep(
     const notCanceled = (o) => !o.canceled_at
 
     throwErrorIf(
-      orderClaim_.fulfillments,
+      orderReturn_.fulfillments,
       notCanceled,
       "All fulfillments must be canceled before canceling a claim"
     )
@@ -89,10 +92,10 @@ export const cancelOrderClaimWorkflowId = "cancel-claim"
 /**
  * This workflow cancels a confirmed order claim. It's used by the
  * [Cancel Claim API Route](https://docs.medusajs.com/api/admin#claims_postclaimsidcancel).
- * 
+ *
  * You can use this workflow within your customizations or your own custom workflows, allowing you to cancel a claim
  * for an order in your custom flows.
- * 
+ *
  * @example
  * const { result } = await cancelOrderClaimWorkflow(container)
  * .run({
@@ -100,9 +103,9 @@ export const cancelOrderClaimWorkflowId = "cancel-claim"
  *     claim_id: "claim_123",
  *   }
  * })
- * 
+ *
  * @summary
- * 
+ *
  * Cancel a confirmed order claim.
  */
 export const cancelOrderClaimWorkflow = createWorkflow(
@@ -110,23 +113,29 @@ export const cancelOrderClaimWorkflow = createWorkflow(
   (
     input: WorkflowData<OrderWorkflow.CancelOrderClaimWorkflowInput>
   ): WorkflowData<void> => {
-    const orderClaim: OrderClaimDTO & { fulfillments: FulfillmentDTO[] } =
+    const orderClaim: OrderClaimDTO = useRemoteQueryStep({
+      entry_point: "order_claim",
+      fields: [
+        "id",
+        "order_id",
+        "return_id",
+        "canceled_at",
+        "additional_items.item_id",
+      ],
+      variables: { id: input.claim_id },
+      list: false,
+      throw_if_key_not_found: true,
+    }).config({ name: "claim-query" })
+
+    const orderReturn: ReturnDTO & { fulfillments: FulfillmentDTO[] } =
       useRemoteQueryStep({
-        entry_point: "order_claim",
-        fields: [
-          "id",
-          "order_id",
-          "return_id",
-          "canceled_at",
-          "fulfillments.canceled_at",
-          "additional_items.item_id",
-        ],
-        variables: { id: input.claim_id },
+        entry_point: "return",
+        fields: ["id", "fulfillments.canceled_at"],
+        variables: { id: orderClaim.return_id },
         list: false,
-        throw_if_key_not_found: true,
-      })
+      }).config({ name: "return-query" })
 
-    cancelClaimValidateOrderStep({ orderClaim, input })
+    cancelClaimValidateOrderStep({ orderClaim, orderReturn, input })
 
     const lineItemIds = transform({ orderClaim }, ({ orderClaim }) => {
       return orderClaim.additional_items?.map((i) => i.item_id)
diff --git a/packages/core/core-flows/src/order/workflows/exchange/cancel-exchange.ts b/packages/core/core-flows/src/order/workflows/exchange/cancel-exchange.ts
index fdec827791c33..48752f3413c56 100644
--- a/packages/core/core-flows/src/order/workflows/exchange/cancel-exchange.ts
+++ b/packages/core/core-flows/src/order/workflows/exchange/cancel-exchange.ts
@@ -2,6 +2,7 @@ import {
   FulfillmentDTO,
   OrderExchangeDTO,
   OrderWorkflow,
+  ReturnDTO,
 } from "@medusajs/framework/types"
 import { MedusaError } from "@medusajs/framework/utils"
 import {
@@ -26,6 +27,10 @@ export type CancelExchangeValidateOrderStepInput = {
    * The order exchange's details.
    */
   orderExchange: OrderExchangeDTO
+  /**
+   * The order return's details.
+   */
+  orderReturn: ReturnDTO & { fulfillments: FulfillmentDTO[] }
   /**
    * The details of canceling the exchange.
    */
@@ -35,14 +40,14 @@ export type CancelExchangeValidateOrderStepInput = {
 /**
  * This step validates that an exchange can be canceled.
  * If the exchange is canceled, or any of the fulfillments are not canceled, the step will throw an error.
- * 
+ *
  * :::note
- * 
+ *
  * You can retrieve an order exchange's details using [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query),
  * or [useQueryGraphStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/useQueryGraphStep).
- * 
+ *
  * :::
- * 
+ *
  * @example
  * const data = cancelExchangeValidateOrder({
  *   orderExchange: {
@@ -56,10 +61,8 @@ export type CancelExchangeValidateOrderStepInput = {
  */
 export const cancelExchangeValidateOrder = createStep(
   "validate-exchange",
-  ({
-    orderExchange,
-  }: CancelExchangeValidateOrderStepInput) => {
-    const orderExchange_ = orderExchange as OrderExchangeDTO & {
+  ({ orderExchange, orderReturn }: CancelExchangeValidateOrderStepInput) => {
+    const orderReturn_ = orderReturn as ReturnDTO & {
       fulfillments: FulfillmentDTO[]
     }
 
@@ -78,7 +81,7 @@ export const cancelExchangeValidateOrder = createStep(
     const notCanceled = (o) => !o.canceled_at
 
     throwErrorIf(
-      orderExchange_.fulfillments,
+      orderReturn_.fulfillments,
       notCanceled,
       "All fulfillments must be canceled before canceling am exchange"
     )
@@ -89,10 +92,10 @@ export const cancelOrderExchangeWorkflowId = "cancel-exchange"
 /**
  * This workflow cancels a confirmed exchange. It's used by the
  * [Cancel Exchange Admin API Route](https://docs.medusajs.com/api/admin#exchanges_postexchangesidcancel).
- * 
+ *
  * You can use this workflow within your customizations or your own custom workflows, allowing you to cancel an exchange
  * for an order in your custom flow.
- * 
+ *
  * @example
  * const { result } = await cancelOrderExchangeWorkflow(container)
  * .run({
@@ -100,9 +103,9 @@ export const cancelOrderExchangeWorkflowId = "cancel-exchange"
  *     exchange_id: "exchange_123",
  *   }
  * })
- * 
+ *
  * @summary
- * 
+ *
  * Cancel an exchange for an order.
  */
 export const cancelOrderExchangeWorkflow = createWorkflow(
@@ -118,7 +121,6 @@ export const cancelOrderExchangeWorkflow = createWorkflow(
           "order_id",
           "return_id",
           "canceled_at",
-          "fulfillments.canceled_at",
           "additional_items.item_id",
         ],
         variables: { id: input.exchange_id },
@@ -126,7 +128,15 @@ export const cancelOrderExchangeWorkflow = createWorkflow(
         throw_if_key_not_found: true,
       })
 
-    cancelExchangeValidateOrder({ orderExchange, input })
+    const orderReturn: ReturnDTO & { fulfillments: FulfillmentDTO[] } =
+      useRemoteQueryStep({
+        entry_point: "return",
+        fields: ["id", "fulfillments.canceled_at"],
+        variables: { id: orderExchange.return_id },
+        list: false,
+      }).config({ name: "return-query" })
+
+    cancelExchangeValidateOrder({ orderExchange, orderReturn, input })
 
     const lineItemIds = transform({ orderExchange }, ({ orderExchange }) => {
       return orderExchange.additional_items?.map((i) => i.item_id)
diff --git a/packages/core/core-flows/src/order/workflows/return/confirm-return-request.ts b/packages/core/core-flows/src/order/workflows/return/confirm-return-request.ts
index ac3c8ce212c57..a03207c5b8fcc 100644
--- a/packages/core/core-flows/src/order/workflows/return/confirm-return-request.ts
+++ b/packages/core/core-flows/src/order/workflows/return/confirm-return-request.ts
@@ -169,26 +169,25 @@ function prepareFulfillmentData({
 }
 
 function extractReturnShippingOptionId({ orderPreview, orderReturn }) {
-  let returnShippingMethod
   for (const shippingMethod of orderPreview.shipping_methods ?? []) {
     const modifiedShippingMethod_ = shippingMethod as any
     if (!modifiedShippingMethod_.actions) {
       continue
     }
 
-    returnShippingMethod = modifiedShippingMethod_.actions.find((action) => {
+    const methodAction = modifiedShippingMethod_.actions.find((action) => {
       return (
         action.action === ChangeActionType.SHIPPING_ADD &&
         action.return_id === orderReturn.id
       )
     })
-  }
 
-  if (!returnShippingMethod) {
-    return null
+    if (methodAction) {
+      return modifiedShippingMethod_.shipping_option_id
+    }
   }
 
-  return returnShippingMethod.shipping_option_id
+  return null
 }
 
 function getUpdateReturnData({ orderReturn }: { orderReturn: { id: string } }) {
diff --git a/packages/modules/link-modules/src/definitions/order-return-fulfillment.ts b/packages/modules/link-modules/src/definitions/order-return-fulfillment.ts
index 180ee5cd8a424..f6a9e76c6ef18 100644
--- a/packages/modules/link-modules/src/definitions/order-return-fulfillment.ts
+++ b/packages/modules/link-modules/src/definitions/order-return-fulfillment.ts
@@ -43,13 +43,13 @@ export const ReturnFulfillment: ModuleJoinerConfig = {
       serviceName: Modules.ORDER,
       entity: "Return",
       fieldAlias: {
-        return_fulfillments: {
+        fulfillments: {
           path: "return_fulfillment_link.fulfillments",
           isList: true,
         },
       },
       relationship: {
-        serviceName: LINKS.OrderFulfillment,
+        serviceName: LINKS.ReturnFulfillment,
         primaryKey: "return_id",
         foreignKey: "id",
         alias: "return_fulfillment_link",
@@ -60,7 +60,7 @@ export const ReturnFulfillment: ModuleJoinerConfig = {
       serviceName: Modules.FULFILLMENT,
       entity: "Fulfillment",
       relationship: {
-        serviceName: LINKS.OrderFulfillment,
+        serviceName: LINKS.ReturnFulfillment,
         primaryKey: "fulfillment_id",
         foreignKey: "id",
         alias: "return_link",


Reviews:
user: login: olivermrbl
body: LGTM, should we add a test?
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-20T18:40:06Z
user: login: olivermrbl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T10:26:27Z
user: login: fPolic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T11:07:56Z
user: login: olivermrbl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T11:18:00Z
user: login: fPolic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T11:27:38Z
user: login: olivermrbl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T12:02:48Z
user: login: trevster344
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-27T18:17:57Z

Review comments:
diff_hunk: @@ -78,7 +81,7 @@ export const cancelClaimValidateOrderStep = createStep(
     const notCanceled = (o) => !o.canceled_at
 
     throwErrorIf(
-      orderClaim_.fulfillments,
+      orderReturn_.fulfillments,
path: packages/core/core-flows/src/order/workflows/claim/cancel-claim.ts
user: login: olivermrbl
body: question: Don't we still need to ensure the claims fulfillments are canceled too? Or am I missing something?
created_at: 2025-04-22T10:26:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -78,7 +81,7 @@ export const cancelClaimValidateOrderStep = createStep(
     const notCanceled = (o) => !o.canceled_at
 
     throwErrorIf(
-      orderClaim_.fulfillments,
+      orderReturn_.fulfillments,
path: packages/core/core-flows/src/order/workflows/claim/cancel-claim.ts
user: login: fPolic
body: We don't have claim/exchange specific fulfillments i.e. we don't have links between those entities AFAIK. We have Return <> Fulfillment link for ReturnFulfillments otherwise it's an order fulillment. Maybe @carlos-r-l-rodrigues can confirm.
created_at: 2025-04-22T11:07:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -78,7 +81,7 @@ export const cancelClaimValidateOrderStep = createStep(
     const notCanceled = (o) => !o.canceled_at
 
     throwErrorIf(
-      orderClaim_.fulfillments,
+      orderReturn_.fulfillments,
path: packages/core/core-flows/src/order/workflows/claim/cancel-claim.ts
user: login: olivermrbl
body: Yeah, but what I mean is, if you create an exchange or claim, and you then create the fulfillment for those outbound items. Those fulfillments would need to be canceled as well before you can cancel the entire exchange or claim. 

Does that make sense?
created_at: 2025-04-22T11:18:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -78,7 +81,7 @@ export const cancelClaimValidateOrderStep = createStep(
     const notCanceled = (o) => !o.canceled_at
 
     throwErrorIf(
-      orderClaim_.fulfillments,
+      orderReturn_.fulfillments,
path: packages/core/core-flows/src/order/workflows/claim/cancel-claim.ts
user: login: fPolic
body: Yeah sorry misunderstud what part of the flow you are reffering to. Makes sense!

So we would need to ensure that any fulfillment on the order that has outbound items from the claim is canceled, right?

This is not handled at the moment. I would suggest to add this in a follow up to not block this fix if you agree?
created_at: 2025-04-22T11:27:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -78,7 +81,7 @@ export const cancelClaimValidateOrderStep = createStep(
     const notCanceled = (o) => !o.canceled_at
 
     throwErrorIf(
-      orderClaim_.fulfillments,
+      orderReturn_.fulfillments,
path: packages/core/core-flows/src/order/workflows/claim/cancel-claim.ts
user: login: olivermrbl
body: > So we would need to ensure that any fulfillment on the order that has outbound items from the claim is canceled, right?

Yes, exactly.

> This is not handled at the moment. I would suggest to add this in a follow up to not block this fix if you agree?

Sure, we can do that. So I guess what we already had in place wasn't working because the fulfillments weren't tied to the claims and exchanges? Is that correct?


created_at: 2025-04-22T12:02:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -78,7 +81,7 @@ export const cancelClaimValidateOrderStep = createStep(
     const notCanceled = (o) => !o.canceled_at
 
     throwErrorIf(
-      orderClaim_.fulfillments,
+      orderReturn_.fulfillments,
path: packages/core/core-flows/src/order/workflows/claim/cancel-claim.ts
user: login: trevster344
body: Any idea on a timeframe for this fix? Currently running into this issue in production.
created_at: 2025-05-27T18:17:57Z
author_association: CONTRIBUTOR

PR comments:
user: login: vercel[bot]
created_at: 2025-04-17T16:15:54Z
body: [vc]: #o+iVKpwjJux5jUn9duWtY9Rc8FGf3+Cq/ppAjBBI2nk=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJtZWR1c2EtZG9jcyIsInJvb3REaXJlY3RvcnkiOiJ3d3cvYXBwcy9kb2NzIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL21lZHVzYWpzL21lZHVzYS1kb2NzL0J3anhYeVZxRXZnbmVIOWNIRmhkUGNXeEt5Y3AiLCJwcmV2aWV3VXJsIjoibWVkdXNhLWRvY3MtZ2l0LWZpeC1yZXR1cm4tZnVsaWZsbG1lbnQtY3JlYXRpb24tbWVkdXNhanMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJJR05PUkVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6IiJ9fSx7Im5hbWUiOiJhcGktcmVmZXJlbmNlIiwicm9vdERpcmVjdG9yeSI6Ind3dy9hcHBzL2FwaS1yZWZlcmVuY2UiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vbWVkdXNhanMvYXBpLXJlZmVyZW5jZS9EaG5VQlFxQm82Y3I5TkxwVHUzbnhpN0Q1RTF5IiwicHJldmlld1VybCI6ImFwaS1yZWZlcmVuY2UtZ2l0LWZpeC1yZXR1cm4tZnVsaWZsbG1lbnQtY3JlYXRpb24tbWVkdXNhanMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJQRU5ESU5HIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6ImFwaS1yZWZlcmVuY2UtZ2l0LWZpeC1yZXR1cm4tZnVsaWZsbG1lbnQtY3JlYXRpb24tbWVkdXNhanMudmVyY2VsLmFwcCJ9fSx7Im5hbWUiOiJkb2NzLXVpIiwicm9vdERpcmVjdG9yeSI6Ind3dy9hcHBzL3VpIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL21lZHVzYWpzL2RvY3MtdWkvRG1hYTJxMjYzeWhzdXZ6Vm11cnhEMkpCZjQyWiIsInByZXZpZXdVcmwiOiJkb2NzLXVpLWdpdC1maXgtcmV0dXJuLWZ1bGlmbGxtZW50LWNyZWF0aW9uLW1lZHVzYWpzLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiSUdOT1JFRCIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiIifX0seyJuYW1lIjoibWVkdXNhLWRhc2hib2FyZCIsInJvb3REaXJlY3RvcnkiOiJwYWNrYWdlcy9hZG1pbi9kYXNoYm9hcmQiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vbWVkdXNhanMvbWVkdXNhLWRhc2hib2FyZC9DNXBNeFFHdEJUaDlhRWRvaWl5RTVYTk5OTmNoIiwicHJldmlld1VybCI6Im1lZHVzYS1kYXNoYm9hcmQtZ2l0LWZpeC1yZXR1cm4tZnVsaWZsbG1lbnQtY3JlYXRpb24tbWVkdXNhanMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJERVBMT1lFRCIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJtZWR1c2EtZGFzaGJvYXJkLWdpdC1maXgtcmV0dXJuLWZ1bGlmbGxtZW50LWNyZWF0aW9uLW1lZHVzYWpzLnZlcmNlbC5hcHAifX0seyJuYW1lIjoicmVzb3VyY2VzLWRvY3MiLCJyb290RGlyZWN0b3J5Ijoid3d3L2FwcHMvcmVzb3VyY2VzIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL21lZHVzYWpzL3Jlc291cmNlcy1kb2NzL0ZuSDVkQXJZRm9CNDZYSFd1R2drNDhmcHdFYkoiLCJwcmV2aWV3VXJsIjoicmVzb3VyY2VzLWRvY3MtZ2l0LWZpeC1yZXR1cm4tZnVsaWZsbG1lbnQtY3JlYXRpb24tbWVkdXNhanMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJJR05PUkVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6IiJ9fSx7Im5hbWUiOiJhcGktcmVmZXJlbmNlLXYyIiwicm9vdERpcmVjdG9yeSI6Ind3dy9hcHBzL2FwaS1yZWZlcmVuY2UiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vbWVkdXNhanMvYXBpLXJlZmVyZW5jZS12Mi9FbTh1UDVKVGp6VmVyaG16YmlSem5IWks4a2tCIiwicHJldmlld1VybCI6ImFwaS1yZWZlcmVuY2UtdjItZ2l0LWZpeC1yZXR1cm4tZnVsaWZsbG1lbnQtY3JlYXRpb24tbWVkdXNhanMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJJR05PUkVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6IiJ9fSx7Im5hbWUiOiJkb2NzLXYyIiwicm9vdERpcmVjdG9yeSI6Ind3dy9hcHBzL2Jvb2siLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vbWVkdXNhanMvZG9jcy12Mi81Mjk1Q3RxVkc3WnpUSEVTVnFhZXFhclRrQ3haIiwicHJldmlld1VybCI6ImRvY3MtdjItZ2l0LWZpeC1yZXR1cm4tZnVsaWZsbG1lbnQtY3JlYXRpb24tbWVkdXNhanMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJJR05PUkVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6IiJ9fSx7Im5hbWUiOiJ1c2VyLWd1aWRlIiwicm9vdERpcmVjdG9yeSI6Ind3dy9hcHBzL3VzZXItZ3VpZGUiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vbWVkdXNhanMvdXNlci1ndWlkZS9CVGllZmREYnB6WTRTWG5QR2dMNmUxNlNWUzZMIiwicHJldmlld1VybCI6InVzZXItZ3VpZGUtZ2l0LWZpeC1yZXR1cm4tZnVsaWZsbG1lbnQtY3JlYXRpb24tbWVkdXNhanMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJJR05PUkVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6IiJ9fV19
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **api-reference** | 🔄 Building ([Inspect](https://vercel.com/medusajs/api-reference/DhnUBQqBo6cr9NLpTu3nxi7D5E1y)) | [Visit Preview](https://api-reference-git-fix-return-fulifllment-creation-medusajs.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/api-reference-git-fix-return-fulifllment-creation-medusajs.vercel.app?via=pr-comment-feedback-link) | Apr 22, 2025 8:16am |
| **medusa-dashboard** | ✅ Ready ([Inspect](https://vercel.com/medusajs/medusa-dashboard/C5pMxQGtBTh9aEdoiiyE5XNNNNch)) | [Visit Preview](https://medusa-dashboard-git-fix-return-fulifllment-creation-medusajs.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/medusa-dashboard-git-fix-return-fulifllment-creation-medusajs.vercel.app?via=pr-comment-feedback-link) | Apr 22, 2025 8:16am |

<details><summary>6 Skipped Deployments</summary>

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **api-reference-v2** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/api-reference-v2/Em8uP5JTjzVerhmzbiRznHZK8kkB)) | [Visit Preview](https://api-reference-v2-git-fix-return-fulifllment-creation-medusajs.vercel.app) |  | Apr 22, 2025 8:16am |
| **docs-ui** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/docs-ui/Dmaa2q263yhsuvzVmurxD2JBf42Z)) | [Visit Preview](https://docs-ui-git-fix-return-fulifllment-creation-medusajs.vercel.app) |  | Apr 22, 2025 8:16am |
| **docs-v2** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/docs-v2/5295CtqVG7ZzTHESVqaeqarTkCxZ)) | [Visit Preview](https://docs-v2-git-fix-return-fulifllment-creation-medusajs.vercel.app) |  | Apr 22, 2025 8:16am |
| **medusa-docs** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/medusa-docs/BwjxXyVqEvgneH9cHFhdPcWxKycp)) | [Visit Preview](https://medusa-docs-git-fix-return-fulifllment-creation-medusajs.vercel.app) |  | Apr 22, 2025 8:16am |
| **resources-docs** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/resources-docs/FnH5dArYFoB46XHWuGgk48fpwEbJ)) | [Visit Preview](https://resources-docs-git-fix-return-fulifllment-creation-medusajs.vercel.app) |  | Apr 22, 2025 8:16am |
| **user-guide** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/user-guide/BTiefdDbpzY4SXnPGgL6e16SVS6L)) | [Visit Preview](https://user-guide-git-fix-return-fulifllment-creation-medusajs.vercel.app) |  | Apr 22, 2025 8:16am |
</details>









author_association: NONE
user: login: changeset-bot[bot]
created_at: 2025-04-17T16:15:54Z
body: ###  🦋  Changeset detected

Latest commit: 3110ca2ee774a709ccaaf08e4f6ae3fcee61ad6d

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 66 packages</summary>

  | Name                               | Type  |
| ---------------------------------- | ----- |
| @medusajs/core-flows               | Patch |
| @medusajs/medusa                   | Patch |
| integration-tests-http             | Patch |
| @medusajs/test-utils               | Patch |
| @medusajs/medusa-oas-cli           | Patch |
| @medusajs/api-key                  | Patch |
| @medusajs/auth                     | Patch |
| @medusajs/cart                     | Patch |
| @medusajs/currency                 | Patch |
| @medusajs/customer                 | Patch |
| @medusajs/file                     | Patch |
| @medusajs/fulfillment              | Patch |
| @medusajs/index                    | Patch |
| @medusajs/inventory                | Patch |
| @medusajs/link-modules             | Patch |
| @medusajs/locking                  | Patch |
| @medusajs/notification             | Patch |
| @medusajs/order                    | Patch |
| @medusajs/payment                  | Patch |
| @medusajs/pricing                  | Patch |
| @medusajs/product                  | Patch |
| @medusajs/promotion                | Patch |
| @medusajs/region                   | Patch |
| @medusajs/sales-channel            | Patch |
| @medusajs/stock-location           | Patch |
| @medusajs/store                    | Patch |
| @medusajs/tax                      | Patch |
| @medusajs/user                     | Patch |
| @medusajs/workflow-engine-inmemory | Patch |
| @medusajs/workflow-engine-redis    | Patch |
| @medusajs/oas-github-ci            | Patch |
| @medusajs/cache-inmemory           | Patch |
| @medusajs/cache-redis              | Patch |
| @medusajs/event-bus-local          | Patch |
| @medusajs/event-bus-redis          | Patch |
| @medusajs/auth-emailpass           | Patch |
| @medusajs/auth-github              | Patch |
| @medusajs/auth-google              | Patch |
| @medusajs/file-local               | Patch |
| @medusajs/file-s3                  | Patch |
| @medusajs/fulfillment-manual       | Patch |
| @medusajs/locking-postgres         | Patch |
| @medusajs/locking-redis            | Patch |
| @medusajs/notification-local       | Patch |
| @medusajs/notification-sendgrid    | Patch |
| @medusajs/payment-stripe           | Patch |
| @medusajs/framework                | Patch |
| @medusajs/js-sdk                   | Patch |
| @medusajs/modules-sdk              | Patch |
| @medusajs/orchestration            | Patch |
| @medusajs/types                    | Patch |
| @medusajs/utils                    | Patch |
| @medusajs/workflows-sdk            | Patch |
| @medusajs/cli                      | Patch |
| @medusajs/telemetry                | Patch |
| @medusajs/admin-bundler            | Patch |
| @medusajs/admin-sdk                | Patch |
| @medusajs/admin-shared             | Patch |
| @medusajs/admin-vite-plugin        | Patch |
| @medusajs/dashboard                | Patch |
| @medusajs/icons                    | Patch |
| @medusajs/toolbox                  | Patch |
| @medusajs/ui-preset                | Patch |
| create-medusa-app                  | Patch |
| medusa-dev-cli                     | Patch |
| @medusajs/ui                       | Patch |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/medusajs/medusa/new/fix/return-fulifllment-creation?filename=.changeset/rude-crews-deliver.md&value=---%0A%22%40medusajs%2Flink-modules%22%3A%20patch%0A%22%40medusajs%2Fcore-flows%22%3A%20patch%0A%22%40medusajs%2Fdashboard%22%3A%20patch%0A%22integration-tests-http%22%3A%20patch%0A---%0A%0Afix(core-flows%2C%20link-modules)%3A%20return%20fulfillment%20creation%0A)


author_association: NONE
user: login: fPolic
created_at: 2025-04-17T17:21:32Z
body: /snapshot-this
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-17T17:28:54Z
body: #### :rocket: A snapshot release has been made for this PR

Test the snapshots by updating your `package.json` with the newly published versions:
```sh
yarn add @medusajs/admin-bundler@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/admin-sdk@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/admin-shared@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/admin-vite-plugin@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/dashboard@2.7.1-snapshot-20250417172656
```
```sh
yarn add create-medusa-app@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/cli@2.7.1-snapshot-20250417172656
```
```sh
yarn add medusa-dev-cli@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/medusa-oas-cli@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/core-flows@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/framework@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/js-sdk@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/modules-sdk@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/orchestration@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/types@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/utils@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/workflows-sdk@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/icons@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/ui@4.0.9-snapshot-20250417172656
```
```sh
yarn add @medusajs/ui-preset@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/medusa@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/telemetry@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/test-utils@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/api-key@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/auth@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/cache-inmemory@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/cache-redis@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/cart@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/currency@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/customer@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/event-bus-local@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/event-bus-redis@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/file@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/fulfillment@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/index@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/inventory@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/link-modules@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/locking@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/notification@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/order@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/payment@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/pricing@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/product@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/promotion@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/auth-emailpass@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/auth-github@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/auth-google@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/file-local@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/file-s3@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/fulfillment-manual@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/locking-postgres@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/locking-redis@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/notification-local@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/notification-sendgrid@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/payment-stripe@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/region@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/sales-channel@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/stock-location@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/store@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/tax@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/user@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/workflow-engine-inmemory@2.7.1-snapshot-20250417172656
```
```sh
yarn add @medusajs/workflow-engine-redis@2.7.1-snapshot-20250417172656
```

> Latest commit: 6a9417a1bb7fc9f60e44e15ac89ca2354d848923
author_association: CONTRIBUTOR
user: login: fPolic
created_at: 2025-04-22T08:33:31Z
body: @olivermrbl, added testing for this and fixed issues causing failed tests, should be ready for merge
author_association: CONTRIBUTOR