Repository: medusajs/medusa
Pull request #11891: feat: Set pricing context hook
Author: login: thetutlage
Labels: name: type: feature
name: team: medusa
Created: 2025-03-18T11:29:00Z | Merged: 2025-03-28T09:47:53Z



Diff:
diff --git a/.changeset/flat-meals-rhyme.md b/.changeset/flat-meals-rhyme.md
new file mode 100644
index 0000000000000..6127fc05d05f5
--- /dev/null
+++ b/.changeset/flat-meals-rhyme.md
@@ -0,0 +1,7 @@
+---
+"@medusajs/core-flows": patch
+"@medusajs/workflows-sdk": patch
+"integration-tests-modules": patch
+---
+
+feat: Set pricing context hook
diff --git a/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts b/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts
index 5bcd57c8d8423..0de6010690e68 100644
--- a/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts
+++ b/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts
@@ -47,6 +47,7 @@ import {
 } from "../../../../helpers/create-admin-user"
 import { seedStorefrontDefaults } from "../../../../helpers/seed-storefront-defaults"
 import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
+import { StepResponse } from "@medusajs/framework/workflows-sdk"
 
 jest.setTimeout(200000)
 
@@ -72,6 +73,7 @@ medusaIntegrationTestRunner({
       let salesChannel
       let defaultRegion
       let customer, storeHeadersWithCustomer
+      let setPricingContextHook: any
 
       beforeAll(async () => {
         appContainer = getContainer()
@@ -90,6 +92,31 @@ medusaIntegrationTestRunner({
           ContainerRegistrationKeys.REMOTE_QUERY
         )
         query = appContainer.resolve(ContainerRegistrationKeys.QUERY)
+
+        createCartWorkflow.hooks.setPricingContext(
+          (input) => {
+            if (setPricingContextHook) {
+              return setPricingContextHook(input)
+            }
+          },
+          () => {}
+        )
+        addToCartWorkflow.hooks.setPricingContext(
+          (input) => {
+            if (setPricingContextHook) {
+              return setPricingContextHook(input)
+            }
+          },
+          () => {}
+        )
+        listShippingOptionsForCartWorkflow.hooks.setPricingContext(
+          (input) => {
+            if (setPricingContextHook) {
+              return setPricingContextHook(input)
+            }
+          },
+          () => {}
+        )
       })
 
       beforeEach(async () => {
@@ -603,28 +630,498 @@ medusaIntegrationTestRunner({
           ])
         })
 
-        it("should throw if sales channel is disabled", async () => {
-          const salesChannel = await scModuleService.createSalesChannels({
-            name: "Webshop",
-            is_disabled: true,
-          })
+        it("should throw if sales channel is disabled", async () => {
+          const salesChannel = await scModuleService.createSalesChannels({
+            name: "Webshop",
+            is_disabled: true,
+          })
+
+          const { errors } = await createCartWorkflow(appContainer).run({
+            input: {
+              sales_channel_id: salesChannel.id,
+            },
+            throwOnError: false,
+          })
+
+          expect(errors).toEqual([
+            {
+              action: "find-sales-channel",
+              handlerType: "invoke",
+              error: expect.objectContaining({
+                message: `Unable to assign cart to disabled Sales Channel: Webshop`,
+              }),
+            },
+          ])
+        })
+
+        describe("setPricingContext hook", () => {
+          it("should use context provided by the hook", async () => {
+            const region = await regionModuleService.createRegions({
+              name: "US",
+              currency_code: "usd",
+            })
+
+            const salesChannel = await scModuleService.createSalesChannels({
+              name: "Webshop",
+            })
+
+            const location = await stockLocationModule.createStockLocations({
+              name: "Warehouse",
+            })
+
+            const [product] = await productModule.createProducts([
+              {
+                title: "Test product",
+                variants: [
+                  {
+                    title: "Test variant",
+                  },
+                ],
+              },
+            ])
+
+            const inventoryItem = await inventoryModule.createInventoryItems({
+              sku: "inv-1234",
+            })
+
+            await inventoryModule.createInventoryLevels([
+              {
+                inventory_item_id: inventoryItem.id,
+                location_id: location.id,
+                stocked_quantity: 2,
+                reserved_quantity: 0,
+              },
+            ])
+
+            const priceSet = await pricingModule.createPriceSets({
+              prices: [
+                {
+                  amount: 3000,
+                  currency_code: "usd",
+                },
+              ],
+            })
+
+            await pricingModule.createPricePreferences({
+              attribute: "currency_code",
+              value: "usd",
+              is_tax_inclusive: true,
+            })
+
+            await remoteLink.create([
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.PRICING]: {
+                  price_set_id: priceSet.id,
+                },
+              },
+              {
+                [Modules.SALES_CHANNEL]: {
+                  sales_channel_id: salesChannel.id,
+                },
+                [Modules.STOCK_LOCATION]: {
+                  stock_location_id: location.id,
+                },
+              },
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.INVENTORY]: {
+                  inventory_item_id: inventoryItem.id,
+                },
+              },
+            ])
+
+            setPricingContextHook = function (input) {
+              expect(input.region).toEqual(
+                expect.objectContaining({
+                  id: region.id,
+                })
+              )
+              expect(input.variantIds).toEqual([product.variants[0].id])
+              expect(input.salesChannel).toEqual(
+                expect.objectContaining({
+                  id: salesChannel.id,
+                })
+              )
+              expect(input.customerData).toEqual(
+                expect.objectContaining({
+                  email: "tony@stark.com",
+                })
+              )
+
+              return new StepResponse({
+                unit_price: 100,
+              })
+            }
+
+            /**
+             * Tried jest, but for some reasons it is not able to provide
+             * correct arguments passed to the function
+             */
+            let pricingContext: any
+            const originalFn = pricingModule.listPriceSets.bind(pricingModule)
+            pricingModule.listPriceSets = function () {
+              pricingContext = { ...arguments[0].context }
+              return originalFn.bind(pricingModule)(...arguments)
+            }
+
+            const { result } = await createCartWorkflow(appContainer).run({
+              input: {
+                email: "tony@stark.com",
+                currency_code: "usd",
+                region_id: region.id,
+                sales_channel_id: salesChannel.id,
+                items: [
+                  {
+                    variant_id: product.variants[0].id,
+                    quantity: 1,
+                  },
+                ],
+              },
+            })
+
+            setPricingContextHook = undefined
+            pricingModule.listPriceSets = originalFn
+
+            expect(pricingContext).toEqual(
+              expect.objectContaining({
+                unit_price: 100,
+                region_id: region.id,
+                currency_code: "usd",
+              })
+            )
+
+            const cart = await cartModuleService.retrieveCart(result.id, {
+              relations: ["items"],
+            })
+
+            expect(cart).toEqual(
+              expect.objectContaining({
+                currency_code: "usd",
+                email: "tony@stark.com",
+                region_id: region.id,
+                sales_channel_id: salesChannel.id,
+                customer_id: expect.any(String),
+                items: expect.arrayContaining([
+                  expect.objectContaining({
+                    quantity: 1,
+                    unit_price: 3000,
+                    is_tax_inclusive: true,
+                  }),
+                ]),
+              })
+            )
+          })
+
+          it("should not be able to override the 'customer_id', 'region_id', and the 'currency_code' from the setPricingContext hook", async () => {
+            const region = await regionModuleService.createRegions({
+              name: "US",
+              currency_code: "usd",
+            })
+
+            const salesChannel = await scModuleService.createSalesChannels({
+              name: "Webshop",
+            })
+
+            const location = await stockLocationModule.createStockLocations({
+              name: "Warehouse",
+            })
+
+            const [product] = await productModule.createProducts([
+              {
+                title: "Test product",
+                variants: [
+                  {
+                    title: "Test variant",
+                  },
+                ],
+              },
+            ])
+
+            const inventoryItem = await inventoryModule.createInventoryItems({
+              sku: "inv-1234",
+            })
+
+            await inventoryModule.createInventoryLevels([
+              {
+                inventory_item_id: inventoryItem.id,
+                location_id: location.id,
+                stocked_quantity: 2,
+                reserved_quantity: 0,
+              },
+            ])
+
+            const priceSet = await pricingModule.createPriceSets({
+              prices: [
+                {
+                  amount: 3000,
+                  currency_code: "usd",
+                },
+              ],
+            })
+
+            await pricingModule.createPricePreferences({
+              attribute: "currency_code",
+              value: "usd",
+              is_tax_inclusive: true,
+            })
+
+            await remoteLink.create([
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.PRICING]: {
+                  price_set_id: priceSet.id,
+                },
+              },
+              {
+                [Modules.SALES_CHANNEL]: {
+                  sales_channel_id: salesChannel.id,
+                },
+                [Modules.STOCK_LOCATION]: {
+                  stock_location_id: location.id,
+                },
+              },
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.INVENTORY]: {
+                  inventory_item_id: inventoryItem.id,
+                },
+              },
+            ])
+
+            setPricingContextHook = function (input) {
+              expect(input.region).toEqual(
+                expect.objectContaining({
+                  id: region.id,
+                })
+              )
+              expect(input.variantIds).toEqual([product.variants[0].id])
+              expect(input.salesChannel).toEqual(
+                expect.objectContaining({
+                  id: salesChannel.id,
+                })
+              )
+              expect(input.customerData).toEqual(
+                expect.objectContaining({
+                  email: "tony@stark.com",
+                })
+              )
+
+              return new StepResponse({
+                unit_price: 200,
+                currency_code: "inr",
+                customer_id: "1",
+                region_id: "1",
+              })
+            }
+
+            /**
+             * Tried jest, but for some reasons it is not able to provide
+             * correct arguments passed to the function
+             */
+            let pricingContext: any
+            const originalFn = pricingModule.listPriceSets.bind(pricingModule)
+            pricingModule.listPriceSets = function () {
+              pricingContext = { ...arguments[0].context }
+              return originalFn.bind(pricingModule)(...arguments)
+            }
+
+            const { result } = await createCartWorkflow(appContainer).run({
+              input: {
+                email: "tony@stark.com",
+                currency_code: "usd",
+                region_id: region.id,
+                sales_channel_id: salesChannel.id,
+                items: [
+                  {
+                    variant_id: product.variants[0].id,
+                    quantity: 1,
+                  },
+                ],
+              },
+            })
+
+            setPricingContextHook = undefined
+            pricingModule.listPriceSets = originalFn
+
+            expect(pricingContext).toEqual(
+              expect.objectContaining({
+                unit_price: 200,
+                region_id: region.id,
+                currency_code: "usd",
+              })
+            )
+            expect(pricingContext.customer_id).toBeDefined()
+            expect(pricingContext.customer_id).not.toEqual("1")
+
+            const cart = await cartModuleService.retrieveCart(result.id, {
+              relations: ["items"],
+            })
+
+            expect(cart).toEqual(
+              expect.objectContaining({
+                currency_code: "usd",
+                email: "tony@stark.com",
+                region_id: region.id,
+                sales_channel_id: salesChannel.id,
+                customer_id: expect.any(String),
+                items: expect.arrayContaining([
+                  expect.objectContaining({
+                    quantity: 1,
+                    unit_price: 3000,
+                    is_tax_inclusive: true,
+                  }),
+                ]),
+              })
+            )
+          })
+
+          it("should disallow non object response from the setPricingContext hook", async () => {
+            const region = await regionModuleService.createRegions({
+              name: "US",
+              currency_code: "usd",
+            })
+
+            const salesChannel = await scModuleService.createSalesChannels({
+              name: "Webshop",
+            })
+
+            const location = await stockLocationModule.createStockLocations({
+              name: "Warehouse",
+            })
+
+            const [product] = await productModule.createProducts([
+              {
+                title: "Test product",
+                variants: [
+                  {
+                    title: "Test variant",
+                  },
+                ],
+              },
+            ])
+
+            const inventoryItem = await inventoryModule.createInventoryItems({
+              sku: "inv-1234",
+            })
+
+            await inventoryModule.createInventoryLevels([
+              {
+                inventory_item_id: inventoryItem.id,
+                location_id: location.id,
+                stocked_quantity: 2,
+                reserved_quantity: 0,
+              },
+            ])
+
+            const priceSet = await pricingModule.createPriceSets({
+              prices: [
+                {
+                  amount: 3000,
+                  currency_code: "usd",
+                },
+              ],
+            })
+
+            await pricingModule.createPricePreferences({
+              attribute: "currency_code",
+              value: "usd",
+              is_tax_inclusive: true,
+            })
+
+            await remoteLink.create([
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.PRICING]: {
+                  price_set_id: priceSet.id,
+                },
+              },
+              {
+                [Modules.SALES_CHANNEL]: {
+                  sales_channel_id: salesChannel.id,
+                },
+                [Modules.STOCK_LOCATION]: {
+                  stock_location_id: location.id,
+                },
+              },
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.INVENTORY]: {
+                  inventory_item_id: inventoryItem.id,
+                },
+              },
+            ])
+
+            setPricingContextHook = function (input) {
+              expect(input.region).toEqual(
+                expect.objectContaining({
+                  id: region.id,
+                })
+              )
+              expect(input.variantIds).toEqual([product.variants[0].id])
+              expect(input.salesChannel).toEqual(
+                expect.objectContaining({
+                  id: salesChannel.id,
+                })
+              )
+              expect(input.customerData).toEqual(
+                expect.objectContaining({
+                  email: "tony@stark.com",
+                })
+              )
+
+              return new StepResponse([1])
+            }
 
-          const { errors } = await createCartWorkflow(appContainer).run({
-            input: {
-              sales_channel_id: salesChannel.id,
-            },
-            throwOnError: false,
-          })
+            const { errors } = await createCartWorkflow(appContainer).run({
+              throwOnError: false,
+              input: {
+                email: "tony@stark.com",
+                currency_code: "usd",
+                region_id: region.id,
+                sales_channel_id: salesChannel.id,
+                items: [
+                  {
+                    variant_id: product.variants[0].id,
+                    quantity: 1,
+                  },
+                ],
+              },
+            })
 
-          expect(errors).toEqual([
-            {
-              action: "find-sales-channel",
-              handlerType: "invoke",
-              error: expect.objectContaining({
-                message: `Unable to assign cart to disabled Sales Channel: Webshop`,
-              }),
-            },
-          ])
+            setPricingContextHook = undefined
+
+            expect(errors).toHaveLength(1)
+            expect(errors[0]).toEqual(
+              expect.objectContaining({
+                action: "get-setPricingContext-result",
+                handlerType: "invoke",
+                error: expect.objectContaining({
+                  issues: [
+                    {
+                      code: "invalid_type",
+                      expected: "object",
+                      message: "Expected object, received array",
+                      path: [],
+                      received: "array",
+                    },
+                  ],
+                }),
+              })
+            )
+          })
         })
 
         describe("compensation", () => {
@@ -1567,123 +2064,426 @@ medusaIntegrationTestRunner({
             },
           ])
 
-          cart = await cartModuleService.retrieveCart(cart.id, {
-            select: ["id", "region_id", "currency_code", "sales_channel_id"],
-          })
+          cart = await cartModuleService.retrieveCart(cart.id, {
+            select: ["id", "region_id", "currency_code", "sales_channel_id"],
+          })
+
+          await addToCartWorkflow(appContainer).run({
+            input: {
+              items: [
+                {
+                  variant_id: product.variants[0].id,
+                  quantity: 1,
+                },
+              ],
+              cart_id: cart.id,
+            },
+          })
+
+          cart = await cartModuleService.retrieveCart(cart.id, {
+            relations: ["items"],
+          })
+
+          expect(cart).toEqual(
+            expect.objectContaining({
+              id: cart.id,
+              currency_code: "usd",
+              items: expect.arrayContaining([
+                expect.objectContaining({
+                  unit_price: 1500,
+                  is_tax_inclusive: true,
+                  quantity: 1,
+                  title: "Test variant",
+                }),
+              ]),
+            })
+          )
+        })
+
+        it("should throw if no price sets for variant exist", async () => {
+          const salesChannel = await scModuleService.createSalesChannels({
+            name: "Webshop",
+          })
+
+          const location = await stockLocationModule.createStockLocations({
+            name: "Warehouse",
+          })
+
+          let cart = await cartModuleService.createCarts({
+            currency_code: "usd",
+            sales_channel_id: salesChannel.id,
+          })
+
+          const [product] = await productModule.createProducts([
+            {
+              title: "Test product",
+              variants: [
+                {
+                  title: "Test variant",
+                },
+              ],
+            },
+          ])
+
+          const inventoryItem = await inventoryModule.createInventoryItems({
+            sku: "inv-1234",
+          })
+
+          await inventoryModule.createInventoryLevels([
+            {
+              inventory_item_id: inventoryItem.id,
+              location_id: location.id,
+              stocked_quantity: 2,
+              reserved_quantity: 0,
+            },
+          ])
+
+          await remoteLink.create([
+            {
+              [Modules.SALES_CHANNEL]: {
+                sales_channel_id: salesChannel.id,
+              },
+              [Modules.STOCK_LOCATION]: {
+                stock_location_id: location.id,
+              },
+            },
+            {
+              [Modules.PRODUCT]: {
+                variant_id: product.variants[0].id,
+              },
+              [Modules.INVENTORY]: {
+                inventory_item_id: inventoryItem.id,
+              },
+            },
+          ])
+
+          const { errors } = await addToCartWorkflow(appContainer).run({
+            input: {
+              items: [
+                {
+                  variant_id: product.variants[0].id,
+                  quantity: 1,
+                },
+              ],
+              cart_id: cart.id,
+            },
+            throwOnError: false,
+          })
+
+          expect(errors).toEqual([
+            {
+              action: "validate-variant-prices",
+              handlerType: "invoke",
+              error: expect.objectContaining({
+                message: expect.stringContaining(
+                  `Variants with IDs ${product.variants[0].id} do not have a price`
+                ),
+              }),
+            },
+          ])
+        })
+
+        describe("setPricingContext hook", () => {
+          it("should use context provided by the hook", async () => {
+            const salesChannel = await scModuleService.createSalesChannels({
+              name: "Webshop",
+            })
+
+            const location = await stockLocationModule.createStockLocations({
+              name: "Warehouse",
+            })
+
+            let cart = await cartModuleService.createCarts({
+              currency_code: "usd",
+              sales_channel_id: salesChannel.id,
+            })
+
+            const [product] = await productModule.createProducts([
+              {
+                title: "Test product",
+                variants: [
+                  {
+                    title: "Test variant",
+                  },
+                ],
+              },
+            ])
+
+            const inventoryItem = await inventoryModule.createInventoryItems({
+              sku: "inv-1234",
+            })
+
+            await inventoryModule.createInventoryLevels([
+              {
+                inventory_item_id: inventoryItem.id,
+                location_id: location.id,
+                stocked_quantity: 2,
+                reserved_quantity: 0,
+              },
+            ])
+
+            const priceSet = await pricingModule.createPriceSets({
+              prices: [
+                {
+                  amount: 3000,
+                  currency_code: "usd",
+                },
+              ],
+            })
+
+            await pricingModule.createPricePreferences({
+              attribute: "currency_code",
+              value: "usd",
+              is_tax_inclusive: true,
+            })
+
+            await remoteLink.create([
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.PRICING]: {
+                  price_set_id: priceSet.id,
+                },
+              },
+              {
+                [Modules.SALES_CHANNEL]: {
+                  sales_channel_id: salesChannel.id,
+                },
+                [Modules.STOCK_LOCATION]: {
+                  stock_location_id: location.id,
+                },
+              },
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.INVENTORY]: {
+                  inventory_item_id: inventoryItem.id,
+                },
+              },
+            ])
+
+            cart = await cartModuleService.retrieveCart(cart.id, {
+              select: ["id", "region_id", "currency_code", "sales_channel_id"],
+            })
+
+            setPricingContextHook = function (input) {
+              expect(input.cart).toEqual(expect.objectContaining(cart))
+              expect(input.variantIds).toEqual([product.variants[0].id])
+              return new StepResponse({
+                unit_price: 100,
+              })
+            }
+
+            /**
+             * Tried jest, but for some reasons it is not able to provide
+             * correct arguments passed to the function
+             */
+            let pricingContext: any
+            const originalFn = pricingModule.listPriceSets.bind(pricingModule)
+            pricingModule.listPriceSets = function () {
+              pricingContext = { ...arguments[0].context }
+              return originalFn.bind(pricingModule)(...arguments)
+            }
+
+            await addToCartWorkflow(appContainer).run({
+              input: {
+                items: [
+                  {
+                    variant_id: product.variants[0].id,
+                    quantity: 1,
+                  },
+                ],
+                cart_id: cart.id,
+              },
+            })
+
+            setPricingContextHook = undefined
+            pricingModule.listPriceSets = originalFn
 
-          await addToCartWorkflow(appContainer).run({
-            input: {
-              items: [
-                {
-                  variant_id: product.variants[0].id,
-                  quantity: 1,
-                },
-              ],
-              cart_id: cart.id,
-            },
-          })
+            expect(pricingContext).toEqual(
+              expect.objectContaining({
+                unit_price: 100,
+                currency_code: "usd",
+              })
+            )
 
-          cart = await cartModuleService.retrieveCart(cart.id, {
-            relations: ["items"],
+            cart = await cartModuleService.retrieveCart(cart.id, {
+              relations: ["items"],
+            })
+
+            expect(cart).toEqual(
+              expect.objectContaining({
+                id: cart.id,
+                currency_code: "usd",
+                items: expect.arrayContaining([
+                  expect.objectContaining({
+                    unit_price: 3000,
+                    is_tax_inclusive: true,
+                    quantity: 1,
+                    title: "Test variant",
+                  }),
+                ]),
+              })
+            )
           })
 
-          expect(cart).toEqual(
-            expect.objectContaining({
-              id: cart.id,
+          it("should not be able to override the 'customer_id', 'region_id', and the 'currency_code' from the setPricingContext hook", async () => {
+            const salesChannel = await scModuleService.createSalesChannels({
+              name: "Webshop",
+            })
+
+            const location = await stockLocationModule.createStockLocations({
+              name: "Warehouse",
+            })
+
+            let cart = await cartModuleService.createCarts({
               currency_code: "usd",
-              items: expect.arrayContaining([
-                expect.objectContaining({
-                  unit_price: 1500,
-                  is_tax_inclusive: true,
-                  quantity: 1,
-                  title: "Test variant",
-                }),
-              ]),
+              sales_channel_id: salesChannel.id,
             })
-          )
-        })
 
-        it("should throw if no price sets for variant exist", async () => {
-          const salesChannel = await scModuleService.createSalesChannels({
-            name: "Webshop",
-          })
+            const [product] = await productModule.createProducts([
+              {
+                title: "Test product",
+                variants: [
+                  {
+                    title: "Test variant",
+                  },
+                ],
+              },
+            ])
 
-          const location = await stockLocationModule.createStockLocations({
-            name: "Warehouse",
-          })
+            const inventoryItem = await inventoryModule.createInventoryItems({
+              sku: "inv-1234",
+            })
 
-          let cart = await cartModuleService.createCarts({
-            currency_code: "usd",
-            sales_channel_id: salesChannel.id,
-          })
+            await inventoryModule.createInventoryLevels([
+              {
+                inventory_item_id: inventoryItem.id,
+                location_id: location.id,
+                stocked_quantity: 2,
+                reserved_quantity: 0,
+              },
+            ])
 
-          const [product] = await productModule.createProducts([
-            {
-              title: "Test product",
-              variants: [
+            const priceSet = await pricingModule.createPriceSets({
+              prices: [
                 {
-                  title: "Test variant",
+                  amount: 3000,
+                  currency_code: "usd",
                 },
               ],
-            },
-          ])
-
-          const inventoryItem = await inventoryModule.createInventoryItems({
-            sku: "inv-1234",
-          })
+            })
 
-          await inventoryModule.createInventoryLevels([
-            {
-              inventory_item_id: inventoryItem.id,
-              location_id: location.id,
-              stocked_quantity: 2,
-              reserved_quantity: 0,
-            },
-          ])
+            await pricingModule.createPricePreferences({
+              attribute: "currency_code",
+              value: "usd",
+              is_tax_inclusive: true,
+            })
 
-          await remoteLink.create([
-            {
-              [Modules.SALES_CHANNEL]: {
-                sales_channel_id: salesChannel.id,
-              },
-              [Modules.STOCK_LOCATION]: {
-                stock_location_id: location.id,
-              },
-            },
-            {
-              [Modules.PRODUCT]: {
-                variant_id: product.variants[0].id,
+            await remoteLink.create([
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.PRICING]: {
+                  price_set_id: priceSet.id,
+                },
               },
-              [Modules.INVENTORY]: {
-                inventory_item_id: inventoryItem.id,
+              {
+                [Modules.SALES_CHANNEL]: {
+                  sales_channel_id: salesChannel.id,
+                },
+                [Modules.STOCK_LOCATION]: {
+                  stock_location_id: location.id,
+                },
               },
-            },
-          ])
-
-          const { errors } = await addToCartWorkflow(appContainer).run({
-            input: {
-              items: [
-                {
+              {
+                [Modules.PRODUCT]: {
                   variant_id: product.variants[0].id,
-                  quantity: 1,
                 },
+                [Modules.INVENTORY]: {
+                  inventory_item_id: inventoryItem.id,
+                },
+              },
+            ])
+
+            cart = await cartModuleService.retrieveCart(cart.id, {
+              select: [
+                "id",
+                "region_id",
+                "currency_code",
+                "sales_channel_id",
+                "customer_id",
               ],
-              cart_id: cart.id,
-            },
-            throwOnError: false,
-          })
+            })
 
-          expect(errors).toEqual([
-            {
-              action: "validate-variant-prices",
-              handlerType: "invoke",
-              error: expect.objectContaining({
-                message: expect.stringContaining(
-                  `Variants with IDs ${product.variants[0].id} do not have a price`
-                ),
-              }),
-            },
-          ])
+            setPricingContextHook = function (input) {
+              expect(input.cart).toEqual(expect.objectContaining(cart))
+              expect(input.variantIds).toEqual([product.variants[0].id])
+              return new StepResponse({
+                unit_price: 200,
+                currency_code: "inr",
+                customer_id: "1",
+                region_id: "1",
+              })
+            }
+
+            /**
+             * Tried jest, but for some reasons it is not able to provide
+             * correct arguments passed to the function
+             */
+            let pricingContext: any
+            const originalFn = pricingModule.listPriceSets.bind(pricingModule)
+            pricingModule.listPriceSets = function () {
+              pricingContext = { ...arguments[0].context }
+              return originalFn.bind(pricingModule)(...arguments)
+            }
+
+            await addToCartWorkflow(appContainer).run({
+              input: {
+                items: [
+                  {
+                    variant_id: product.variants[0].id,
+                    quantity: 1,
+                  },
+                ],
+                cart_id: cart.id,
+              },
+            })
+
+            setPricingContextHook = undefined
+            pricingModule.listPriceSets = originalFn
+
+            expect(pricingContext).toEqual(
+              expect.objectContaining({
+                unit_price: 200,
+                region_id: cart.region_id,
+                customer_id: cart.customer_id,
+                currency_code: "usd",
+              })
+            )
+
+            cart = await cartModuleService.retrieveCart(cart.id, {
+              relations: ["items"],
+            })
+
+            expect(cart).toEqual(
+              expect.objectContaining({
+                id: cart.id,
+                currency_code: "usd",
+                items: expect.arrayContaining([
+                  expect.objectContaining({
+                    unit_price: 3000,
+                    is_tax_inclusive: true,
+                    quantity: 1,
+                    title: "Test variant",
+                  }),
+                ]),
+              })
+            )
+          })
         })
       })
 
@@ -3493,6 +4293,174 @@ medusaIntegrationTestRunner({
 
           expect(result).toEqual([])
         })
+
+        describe("setPricingContext hook", () => {
+          it("should use context provided by the hook", async () => {
+            const shippingOption = (
+              await api.post(
+                `/admin/shipping-options`,
+                {
+                  name: "Test shipping option",
+                  service_zone_id: fulfillmentSet.service_zones[0].id,
+                  shipping_profile_id: shippingProfile.id,
+                  provider_id: "manual_test-provider",
+                  price_type: "flat",
+                  type: {
+                    label: "Test type",
+                    description: "Test description",
+                    code: "test-code",
+                  },
+                  prices: [
+                    {
+                      amount: 3000,
+                      currency_code: "usd",
+                    },
+                  ],
+                  rules: [
+                    {
+                      operator: RuleOperator.EQ,
+                      attribute: "is_return",
+                      value: "false",
+                    },
+                    {
+                      operator: RuleOperator.EQ,
+                      attribute: "enabled_in_store",
+                      value: "true",
+                    },
+                  ],
+                },
+                adminHeaders
+              )
+            ).data.shipping_option
+
+            cart = (await api.get(`/store/carts/${cart.id}`, storeHeaders)).data
+              .cart
+
+            setPricingContextHook = function (input) {
+              expect(input.cart.id).toEqual(cart.id)
+              return new StepResponse({
+                unit_price: 100,
+              })
+            }
+
+            /**
+             * Tried jest, but for some reasons it is not able to provide
+             * correct arguments passed to the function
+             */
+            let pricingContext: any
+            const originalFn = pricingModule.listPriceSets.bind(pricingModule)
+            pricingModule.listPriceSets = function () {
+              pricingContext = { ...arguments[0].context }
+              return originalFn.bind(pricingModule)(...arguments)
+            }
+
+            const { result } = await listShippingOptionsForCartWorkflow(
+              appContainer
+            ).run({ input: { cart_id: cart.id } })
+
+            setPricingContextHook = undefined
+            pricingModule.listPriceSets = originalFn
+
+            expect(pricingContext).toEqual(
+              expect.objectContaining({
+                unit_price: 100,
+              })
+            )
+
+            expect(result).toEqual([
+              expect.objectContaining({
+                amount: 3000,
+                id: shippingOption.id,
+              }),
+            ])
+          })
+
+          it("should not be able to override the 'customer_id', 'region_id', and the 'currency_code' from the setPricingContext hook", async () => {
+            const shippingOption = (
+              await api.post(
+                `/admin/shipping-options`,
+                {
+                  name: "Test shipping option",
+                  service_zone_id: fulfillmentSet.service_zones[0].id,
+                  shipping_profile_id: shippingProfile.id,
+                  provider_id: "manual_test-provider",
+                  price_type: "flat",
+                  type: {
+                    label: "Test type",
+                    description: "Test description",
+                    code: "test-code",
+                  },
+                  prices: [
+                    {
+                      amount: 3000,
+                      currency_code: "usd",
+                    },
+                  ],
+                  rules: [
+                    {
+                      operator: RuleOperator.EQ,
+                      attribute: "is_return",
+                      value: "false",
+                    },
+                    {
+                      operator: RuleOperator.EQ,
+                      attribute: "enabled_in_store",
+                      value: "true",
+                    },
+                  ],
+                },
+                adminHeaders
+              )
+            ).data.shipping_option
+
+            cart = (await api.get(`/store/carts/${cart.id}`, storeHeaders)).data
+              .cart
+
+            setPricingContextHook = function (input) {
+              expect(input.cart.id).toEqual(cart.id)
+              return new StepResponse({
+                unit_price: 200,
+                currency_code: "inr",
+                customer_id: "1",
+                region_id: "1",
+              })
+            }
+
+            /**
+             * Tried jest, but for some reasons it is not able to provide
+             * correct arguments passed to the function
+             */
+            let pricingContext: any
+            const originalFn = pricingModule.listPriceSets.bind(pricingModule)
+            pricingModule.listPriceSets = function () {
+              pricingContext = { ...arguments[0].context }
+              return originalFn.bind(pricingModule)(...arguments)
+            }
+
+            const { result } = await listShippingOptionsForCartWorkflow(
+              appContainer
+            ).run({ input: { cart_id: cart.id } })
+
+            setPricingContextHook = undefined
+            pricingModule.listPriceSets = originalFn
+
+            expect(pricingContext).toEqual(
+              expect.objectContaining({
+                unit_price: 200,
+                region_id: cart.region_id,
+                customer_id: cart.customer_id,
+                currency_code: "usd",
+              })
+            )
+
+            expect(result).toEqual([
+              expect.objectContaining({
+                amount: 3000,
+                id: shippingOption.id,
+              }),
+            ])
+          })
+        })
       })
 
       describe("updateTaxLinesWorkflow", () => {
diff --git a/packages/core/core-flows/src/cart/utils/schemas.ts b/packages/core/core-flows/src/cart/utils/schemas.ts
new file mode 100644
index 0000000000000..053b8f216b5d4
--- /dev/null
+++ b/packages/core/core-flows/src/cart/utils/schemas.ts
@@ -0,0 +1,2 @@
+import z from "zod"
+export const pricingContextResult = z.record(z.string(), z.any()).optional()
diff --git a/packages/core/core-flows/src/cart/workflows/add-to-cart.ts b/packages/core/core-flows/src/cart/workflows/add-to-cart.ts
index 554856dfe395c..190a963f9475f 100644
--- a/packages/core/core-flows/src/cart/workflows/add-to-cart.ts
+++ b/packages/core/core-flows/src/cart/workflows/add-to-cart.ts
@@ -1,4 +1,5 @@
 import {
+  AdditionalData,
   AddToCartWorkflowInputDTO,
   ConfirmVariantInventoryWorkflowInputDTO,
 } from "@medusajs/framework/types"
@@ -33,6 +34,7 @@ import {
 } from "../utils/prepare-line-item-data"
 import { confirmVariantInventoryWorkflow } from "./confirm-variant-inventory"
 import { refreshCartItemsWorkflow } from "./refresh-cart-items"
+import { pricingContextResult } from "../utils/schemas"
 
 const cartFields = ["completed_at"].concat(cartFieldsForPricingContext)
 
@@ -71,7 +73,7 @@ export const addToCartWorkflowId = "add-to-cart"
  */
 export const addToCartWorkflow = createWorkflow(
   addToCartWorkflowId,
-  (input: WorkflowData<AddToCartWorkflowInputDTO>) => {
+  (input: WorkflowData<AddToCartWorkflowInputDTO & AdditionalData>) => {
     const cartQuery = useQueryGraphStep({
       entity: "cart",
       filters: { id: input.cart_id },
@@ -93,6 +95,35 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        cart,
+        variantIds,
+        items: input.items,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+
+    const setPricingContextResult = setPricingContext.getResult()
+    const pricingContext = transform(
+      { cart, setPricingContextResult },
+      (data) => {
+        return {
+          ...data.cart,
+          ...(data.setPricingContextResult ? data.setPricingContextResult : {}),
+          currency_code: data.cart.currency_code,
+          region_id: data.cart.region_id,
+          region: data.cart.region,
+          customer_id: data.cart.customer_id,
+          customer: data.cart.customer,
+        }
+      }
+    )
+
     const variants = when({ variantIds }, ({ variantIds }) => {
       return !!variantIds.length
     }).then(() => {
@@ -102,7 +133,7 @@ export const addToCartWorkflow = createWorkflow(
         variables: {
           id: variantIds,
           calculated_price: {
-            context: cart,
+            context: pricingContext,
           },
         },
       })
@@ -201,7 +232,7 @@ export const addToCartWorkflow = createWorkflow(
     })
 
     return new WorkflowResponse(void 0, {
-      hooks: [validate],
+      hooks: [validate, setPricingContext] as const,
     })
   }
 )
diff --git a/packages/core/core-flows/src/cart/workflows/create-carts.ts b/packages/core/core-flows/src/cart/workflows/create-carts.ts
index e27ae38ca112a..6e68f3b1b5511 100644
--- a/packages/core/core-flows/src/cart/workflows/create-carts.ts
+++ b/packages/core/core-flows/src/cart/workflows/create-carts.ts
@@ -36,6 +36,7 @@ import { refreshPaymentCollectionForCartWorkflow } from "./refresh-payment-colle
 import { updateCartPromotionsWorkflow } from "./update-cart-promotions"
 import { updateTaxLinesWorkflow } from "./update-tax-lines"
 import { validateSalesChannelStep } from "../steps/validate-sales-channel"
+import { pricingContextResult } from "../utils/schemas"
 
 /**
  * The data to create the cart, along with custom data that's passed to the workflow's hooks.
@@ -98,16 +99,31 @@ export const createCartWorkflow = createWorkflow(
     )
 
     validateSalesChannelStep({ salesChannel })
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        region,
+        variantIds,
+        salesChannel,
+        customerData,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+    const setPricingContextResult = setPricingContext.getResult()
 
     // TODO: This is on par with the context used in v1.*, but we can be more flexible.
     const pricingContext = transform(
-      { input, region, customerData },
+      { input, region, customerData, setPricingContextResult },
       (data) => {
         if (!data.region) {
           throw new MedusaError(MedusaError.Types.NOT_FOUND, "No regions found")
         }
 
         return {
+          ...(data.setPricingContextResult ? data.setPricingContextResult : {}),
           currency_code: data.input.currency_code ?? data.region.currency_code,
           region_id: data.region.id,
           customer_id: data.customerData.customer?.id,
@@ -248,7 +264,7 @@ export const createCartWorkflow = createWorkflow(
     })
 
     return new WorkflowResponse(cart, {
-      hooks: [validate, cartCreated],
+      hooks: [validate, cartCreated, setPricingContext] as const,
     })
   }
 )
diff --git a/packages/core/core-flows/src/cart/workflows/list-shipping-options-for-cart.ts b/packages/core/core-flows/src/cart/workflows/list-shipping-options-for-cart.ts
index c181a6aaa53f8..abdbc339d2f4b 100644
--- a/packages/core/core-flows/src/cart/workflows/list-shipping-options-for-cart.ts
+++ b/packages/core/core-flows/src/cart/workflows/list-shipping-options-for-cart.ts
@@ -1,4 +1,5 @@
 import {
+  createHook,
   createWorkflow,
   transform,
   WorkflowData,
@@ -7,8 +8,12 @@ import {
 import { useQueryGraphStep, validatePresenceOfStep } from "../../common"
 import { useRemoteQueryStep } from "../../common/steps/use-remote-query"
 import { cartFieldsForPricingContext } from "../utils/fields"
-import { ListShippingOptionsForCartWorkflowInput } from "@medusajs/types"
+import {
+  AdditionalData,
+  ListShippingOptionsForCartWorkflowInput,
+} from "@medusajs/types"
 import { isDefined } from "@medusajs/framework/utils"
+import { pricingContextResult } from "../utils/schemas"
 
 export const listShippingOptionsForCartWorkflowId =
   "list-shipping-options-for-cart"
@@ -41,7 +46,11 @@ export const listShippingOptionsForCartWorkflowId =
  */
 export const listShippingOptionsForCartWorkflow = createWorkflow(
   listShippingOptionsForCartWorkflowId,
-  (input: WorkflowData<ListShippingOptionsForCartWorkflowInput>) => {
+  (
+    input: WorkflowData<
+      ListShippingOptionsForCartWorkflowInput & AdditionalData
+    >
+  ) => {
     const cartQuery = useQueryGraphStep({
       entity: "cart",
       filters: { id: input.cart_id },
@@ -96,9 +105,22 @@ export const listShippingOptionsForCartWorkflow = createWorkflow(
       }
     )
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        cart: cart,
+        fulfillmentSetIds,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+    const setPricingContextResult = setPricingContext.getResult()
+
     const queryVariables = transform(
-      { input, fulfillmentSetIds, cart },
-      ({ input, fulfillmentSetIds, cart }) => {
+      { input, fulfillmentSetIds, cart, setPricingContextResult },
+      ({ input, fulfillmentSetIds, cart, setPricingContextResult }) => {
         return {
           id: input.option_ids,
 
@@ -122,7 +144,17 @@ export const listShippingOptionsForCartWorkflow = createWorkflow(
             },
           },
 
-          calculated_price: { context: cart },
+          calculated_price: {
+            context: {
+              ...cart,
+              ...(setPricingContextResult ? setPricingContextResult : {}),
+              currency_code: cart.currency_code,
+              region_id: cart.region_id,
+              region: cart.region,
+              customer_id: cart.customer_id,
+              customer: cart.customer,
+            },
+          },
         }
       }
     )
@@ -202,6 +234,8 @@ export const listShippingOptionsForCartWorkflow = createWorkflow(
         })
     )
 
-    return new WorkflowResponse(shippingOptionsWithPrice)
+    return new WorkflowResponse(shippingOptionsWithPrice, {
+      hooks: [setPricingContext] as const,
+    })
   }
 )
diff --git a/packages/core/core-flows/src/cart/workflows/refresh-cart-items.ts b/packages/core/core-flows/src/cart/workflows/refresh-cart-items.ts
index 53596a117478c..0977daa6d899f 100644
--- a/packages/core/core-flows/src/cart/workflows/refresh-cart-items.ts
+++ b/packages/core/core-flows/src/cart/workflows/refresh-cart-items.ts
@@ -28,6 +28,8 @@ import { refreshPaymentCollectionForCartWorkflow } from "./refresh-payment-colle
 import { updateCartPromotionsWorkflow } from "./update-cart-promotions"
 import { updateTaxLinesWorkflow } from "./update-tax-lines"
 import { upsertTaxLinesWorkflow } from "./upsert-tax-lines"
+import { AdditionalData } from "@medusajs/types"
+import { pricingContextResult } from "../utils/schemas"
 
 /**
  * The details of the cart to refresh.
@@ -91,7 +93,20 @@ export const refreshCartItemsWorkflowId = "refresh-cart-items"
  */
 export const refreshCartItemsWorkflow = createWorkflow(
   refreshCartItemsWorkflowId,
-  (input: WorkflowData<RefreshCartItemsWorkflowInput>) => {
+  (input: WorkflowData<RefreshCartItemsWorkflowInput & AdditionalData>) => {
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        cart_id: input.cart_id,
+        items: input.items,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+    const setPricingContextResult = setPricingContext.getResult()
+
     when({ input }, ({ input }) => {
       return !!input.force_refresh
     }).then(() => {
@@ -106,9 +121,22 @@ export const refreshCartItemsWorkflow = createWorkflow(
         return (data.cart.items ?? []).map((i) => i.variant_id).filter(Boolean)
       })
 
-      const cartPricingContext = transform({ cart }, ({ cart }) => {
-        return filterObjectByKeys(cart, cartFieldsForPricingContext)
-      })
+      const cartPricingContext = transform(
+        { cart, setPricingContextResult },
+        (data) => {
+          return {
+            ...filterObjectByKeys(data.cart, cartFieldsForPricingContext),
+            ...(data.setPricingContextResult
+              ? data.setPricingContextResult
+              : {}),
+            currency_code: data.cart.currency_code,
+            region_id: data.cart.region_id,
+            region: data.cart.region,
+            customer_id: data.cart.customer_id,
+            customer: data.cart.customer,
+          }
+        }
+      )
 
       const variants = useRemoteQueryStep({
         entry_point: "variants",
@@ -235,6 +263,8 @@ export const refreshCartItemsWorkflow = createWorkflow(
       input: { cart_id: input.cart_id },
     })
 
-    return new WorkflowResponse(refetchedCart)
+    return new WorkflowResponse(refetchedCart, {
+      hooks: [setPricingContext] as const,
+    })
   }
 )
diff --git a/packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts b/packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts
index 97631f0c45277..af1d4889df054 100644
--- a/packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts
+++ b/packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts
@@ -1,4 +1,7 @@
-import { UpdateLineItemInCartWorkflowInputDTO } from "@medusajs/framework/types"
+import {
+  AdditionalData,
+  UpdateLineItemInCartWorkflowInputDTO,
+} from "@medusajs/framework/types"
 import { isDefined, MedusaError } from "@medusajs/framework/utils"
 import {
   createHook,
@@ -19,6 +22,7 @@ import {
 } from "../utils/fields"
 import { confirmVariantInventoryWorkflow } from "./confirm-variant-inventory"
 import { refreshCartItemsWorkflow } from "./refresh-cart-items"
+import { pricingContextResult } from "../utils/schemas"
 
 const cartFields = cartFieldsForPricingContext.concat(["items.*"])
 
@@ -26,9 +30,9 @@ export const updateLineItemInCartWorkflowId = "update-line-item-in-cart"
 /**
  * This workflow updates a line item's details in a cart. You can update the line item's quantity, unit price, and more. This workflow is executed
  * by the [Update Line Item Store API Route](https://docs.medusajs.com/api/store#carts_postcartsidlineitemsline_id).
- * 
+ *
  * You can use this workflow within your own customizations or custom workflows, allowing you to update a line item's details in your custom flows.
- * 
+ *
  * @example
  * const { result } = await updateLineItemInCartWorkflow(container)
  * .run({
@@ -40,16 +44,18 @@ export const updateLineItemInCartWorkflowId = "update-line-item-in-cart"
  *     }
  *   }
  * })
- * 
+ *
  * @summary
- * 
+ *
  * Update a cart's line item.
  *
  * @property hooks.validate - This hook is executed before all operations. You can consume this hook to perform any custom validation. If validation fails, you can throw an error to stop the workflow execution.
  */
 export const updateLineItemInCartWorkflow = createWorkflow(
   updateLineItemInCartWorkflowId,
-  (input: WorkflowData<UpdateLineItemInCartWorkflowInputDTO>) => {
+  (
+    input: WorkflowData<UpdateLineItemInCartWorkflowInputDTO & AdditionalData>
+  ) => {
     const cartQuery = useQueryGraphStep({
       entity: "cart",
       filters: { id: input.cart_id },
@@ -73,6 +79,35 @@ export const updateLineItemInCartWorkflow = createWorkflow(
       return [item.variant_id].filter(Boolean)
     })
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        cart,
+        item,
+        variantIds,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+
+    const setPricingContextResult = setPricingContext.getResult()
+    const pricingContext = transform(
+      { cart, setPricingContextResult },
+      (data) => {
+        return {
+          ...data.cart,
+          ...(data.setPricingContextResult ? data.setPricingContextResult : {}),
+          currency_code: data.cart.currency_code,
+          region_id: data.cart.region_id,
+          region: data.cart.region,
+          customer_id: data.cart.customer_id,
+          customer: data.cart.customer,
+        }
+      }
+    )
+
     const variants = when({ variantIds }, ({ variantIds }) => {
       return !!variantIds.length
     }).then(() => {
@@ -82,7 +117,7 @@ export const updateLineItemInCartWorkflow = createWorkflow(
         variables: {
           id: variantIds,
           calculated_price: {
-            context: cart,
+            context: pricingContext,
           },
         },
       }).config({ name: "fetch-variants" })
@@ -98,7 +133,7 @@ export const updateLineItemInCartWorkflow = createWorkflow(
 
     confirmVariantInventoryWorkflow.runAsStep({
       input: {
-        sales_channel_id: cart.sales_channel_id,
+        sales_channel_id: pricingContext.sales_channel_id,
         variants,
         items,
       },
@@ -147,7 +182,7 @@ export const updateLineItemInCartWorkflow = createWorkflow(
     })
 
     return new WorkflowResponse(void 0, {
-      hooks: [validate],
+      hooks: [validate, setPricingContext] as const,
     })
   }
 )
diff --git a/packages/core/core-flows/src/order/utils/fetch-shipping-option.ts b/packages/core/core-flows/src/order/utils/fetch-shipping-option.ts
index 199f228735a89..c41a16cd71fde 100644
--- a/packages/core/core-flows/src/order/utils/fetch-shipping-option.ts
+++ b/packages/core/core-flows/src/order/utils/fetch-shipping-option.ts
@@ -1,4 +1,5 @@
 import {
+  AdditionalData,
   BigNumberInput,
   CalculatedRMAShippingContext,
   CalculateShippingOptionPriceDTO,
@@ -6,6 +7,7 @@ import {
 } from "@medusajs/framework/types"
 import {
   WorkflowResponse,
+  createHook,
   createWorkflow,
   transform,
   when,
@@ -13,6 +15,7 @@ import {
 import { BigNumber, ShippingOptionPriceType } from "@medusajs/framework/utils"
 import { calculateShippingOptionsPricesStep } from "../../fulfillment/steps"
 import { useRemoteQueryStep } from "../../common"
+import { pricingContextResult } from "../../cart/utils/schemas"
 
 const COMMON_OPTIONS_FIELDS = [
   "id",
@@ -90,9 +93,7 @@ export const createOrderEditShippingMethodWorkflowId = "fetch-shipping-option"
  */
 export const fetchShippingOptionForOrderWorkflow = createWorkflow(
   createOrderEditShippingMethodWorkflowId,
-  function (
-    input: FetchShippingOptionForOrderWorkflowInput
-  ): WorkflowResponse<FetchShippingOptionForOrderWorkflowOutput> {
+  function (input: FetchShippingOptionForOrderWorkflowInput & AdditionalData) {
     const initialOption = useRemoteQueryStep({
       entry_point: "shipping_option",
       variables: { id: input.shipping_option_id },
@@ -170,6 +171,20 @@ export const fetchShippingOptionForOrderWorkflow = createWorkflow(
       return shippingOptionsWithPrice
     })
 
+    const setPricingContext = createHook("setPricingContext", input, {
+      resultValidator: pricingContextResult,
+    })
+    const setPricingContextResult = setPricingContext.getResult()
+    const pricingContext = transform(
+      { input, setPricingContextResult },
+      (data) => {
+        return {
+          ...(data.setPricingContextResult ? data.setPricingContextResult : {}),
+          currency_code: data.input.currency_code,
+        }
+      }
+    )
+
     const flatRateShippingOption = when(
       "option-flat",
       { isCalculatedPriceShippingOption },
@@ -186,7 +201,7 @@ export const fetchShippingOptionForOrderWorkflow = createWorkflow(
         variables: {
           id: input.shipping_option_id,
           calculated_price: {
-            context: { currency_code: input.currency_code },
+            context: pricingContext,
           },
         },
         list: false,
@@ -195,7 +210,7 @@ export const fetchShippingOptionForOrderWorkflow = createWorkflow(
       return shippingOption
     })
 
-    const result = transform(
+    const result: FetchShippingOptionForOrderWorkflowOutput = transform(
       {
         calculatedPriceShippingOption,
         flatRateShippingOption,
@@ -205,6 +220,6 @@ export const fetchShippingOptionForOrderWorkflow = createWorkflow(
       }
     )
 
-    return new WorkflowResponse(result)
+    return new WorkflowResponse(result, { hooks: [setPricingContext] as const })
   }
 )
diff --git a/packages/core/core-flows/src/order/workflows/add-line-items.ts b/packages/core/core-flows/src/order/workflows/add-line-items.ts
index b3ad4ca971f91..9c97518bf3377 100644
--- a/packages/core/core-flows/src/order/workflows/add-line-items.ts
+++ b/packages/core/core-flows/src/order/workflows/add-line-items.ts
@@ -1,6 +1,11 @@
-import { OrderLineItemDTO, OrderWorkflow } from "@medusajs/framework/types"
+import {
+  AdditionalData,
+  OrderLineItemDTO,
+  OrderWorkflow,
+} from "@medusajs/framework/types"
 import { isDefined, MedusaError } from "@medusajs/framework/utils"
 import {
+  createHook,
   createWorkflow,
   parallelize,
   transform,
@@ -21,6 +26,7 @@ import { confirmVariantInventoryWorkflow } from "../../cart/workflows/confirm-va
 import { useRemoteQueryStep } from "../../common"
 import { createOrderLineItemsStep } from "../steps"
 import { productVariantsFields } from "../utils/fields"
+import { pricingContextResult } from "../../cart/utils/schemas"
 
 function prepareLineItems(data) {
   const items = (data.input.items ?? []).map((item) => {
@@ -55,12 +61,12 @@ export type OrderAddLineItemWorkflowOutput = OrderLineItemDTO[]
 
 export const addOrderLineItemsWorkflowId = "order-add-line-items"
 /**
- * This workflow adds line items to an order. This is useful when making edits to 
+ * This workflow adds line items to an order. This is useful when making edits to
  * an order. It's used by other workflows, such as {@link orderEditAddNewItemWorkflow}.
- * 
+ *
  * You can use this workflow within your customizations or your own custom workflows, allowing you to wrap custom logic around adding items to
  * an order.
- * 
+ *
  * @example
  * const { result } = await addOrderLineItemsWorkflow(container)
  * .run({
@@ -74,16 +80,18 @@ export const addOrderLineItemsWorkflowId = "order-add-line-items"
  *     ]
  *   }
  * })
- * 
+ *
  * @summary
- * 
+ *
  * Add line items to an order.
  */
 export const addOrderLineItemsWorkflow = createWorkflow(
   addOrderLineItemsWorkflowId,
   (
-    input: WorkflowData<OrderWorkflow.OrderAddLineItemWorkflowInput>
-  ): WorkflowResponse<OrderAddLineItemWorkflowOutput> => {
+    input: WorkflowData<
+      OrderWorkflow.OrderAddLineItemWorkflowInput & AdditionalData
+    >
+  ) => {
     const order = useRemoteQueryStep({
       entry_point: "orders",
       fields: [
@@ -118,14 +126,30 @@ export const addOrderLineItemsWorkflow = createWorkflow(
       })
     )
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        order,
+        variantIds,
+        region,
+        customerData,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+    const setPricingContextResult = setPricingContext.getResult()
+
     const pricingContext = transform(
-      { input, region, customerData, order },
+      { input, region, customerData, order, setPricingContextResult },
       (data) => {
         if (!data.region) {
           throw new MedusaError(MedusaError.Types.NOT_FOUND, "Region not found")
         }
 
         return {
+          ...(data.setPricingContextResult ? data.setPricingContextResult : {}),
           currency_code: data.order.currency_code ?? data.region.currency_code,
           region_id: data.region.id,
           customer_id: data.customerData.customer?.id,
@@ -165,7 +189,10 @@ export const addOrderLineItemsWorkflow = createWorkflow(
     return new WorkflowResponse(
       createOrderLineItemsStep({
         items: lineItems,
-      })
+      }) satisfies OrderAddLineItemWorkflowOutput,
+      {
+        hooks: [setPricingContext] as const,
+      }
     )
   }
 )
diff --git a/packages/core/core-flows/src/order/workflows/claim/update-claim-shipping-method.ts b/packages/core/core-flows/src/order/workflows/claim/update-claim-shipping-method.ts
index 6a0620b1fc2e6..584b233a4d3ca 100644
--- a/packages/core/core-flows/src/order/workflows/claim/update-claim-shipping-method.ts
+++ b/packages/core/core-flows/src/order/workflows/claim/update-claim-shipping-method.ts
@@ -1,4 +1,5 @@
 import {
+  AdditionalData,
   OrderChangeActionDTO,
   OrderChangeDTO,
   OrderClaimDTO,
@@ -9,6 +10,7 @@ import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
 import {
   WorkflowData,
   WorkflowResponse,
+  createHook,
   createStep,
   createWorkflow,
   parallelize,
@@ -26,6 +28,7 @@ import {
   throwIfOrderChangeIsNotActive,
 } from "../../utils/order-validation"
 import { prepareShippingMethodUpdate } from "../../utils/prepare-shipping-method"
+import { pricingContextResult } from "../../../cart/utils/schemas"
 
 /**
  * The data to validate that a claim's shipping method can be updated.
@@ -42,21 +45,24 @@ export type UpdateClaimShippingMethodValidationStepInput = {
   /**
    * The details of updating the shipping method.
    */
-  input: Pick<OrderWorkflow.UpdateClaimShippingMethodWorkflowInput, "claim_id" | "action_id">
+  input: Pick<
+    OrderWorkflow.UpdateClaimShippingMethodWorkflowInput,
+    "claim_id" | "action_id"
+  >
 }
 
 /**
  * This step validates that a claim's shipping method can be updated.
  * If the claim is canceled, the order change is not active, the shipping method isn't added to the claim,
  * or the action is not adding a shipping method, the step will throw an error.
- * 
+ *
  * :::note
- * 
+ *
  * You can retrieve an order claim and order change 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 = updateClaimShippingMethodValidationStep({
  *   orderChange: {
@@ -105,10 +111,10 @@ export const updateClaimShippingMethodWorkflowId =
  * This workflow updates a claim's inbound (return) or outbound (delivery of new items) shipping method.
  * It's used by the [Update Inbound Shipping Admin API Route](https://docs.medusajs.com/api/admin#claims_postclaimsidinboundshippingmethodaction_id),
  * and the [Update Outbound Shipping Admin API Route](https://docs.medusajs.com/api/admin#claims_postclaimsidoutboundshippingmethodaction_id).
- * 
+ *
  * You can use this workflow within your customizations or your own custom workflows, allowing you to update a claim's shipping method
  * in your own custom flows.
- * 
+ *
  * @example
  * const { result } = await updateClaimShippingMethodWorkflow(container)
  * .run({
@@ -120,16 +126,18 @@ export const updateClaimShippingMethodWorkflowId =
  *     }
  *   }
  * })
- * 
+ *
  * @summary
- * 
+ *
  * Update an inbound or outbound shipping method of a claim.
  */
 export const updateClaimShippingMethodWorkflow = createWorkflow(
   updateClaimShippingMethodWorkflowId,
   function (
-    input: WorkflowData<OrderWorkflow.UpdateClaimShippingMethodWorkflowInput>
-  ): WorkflowResponse<OrderPreviewDTO> {
+    input: WorkflowData<
+      OrderWorkflow.UpdateClaimShippingMethodWorkflowInput & AdditionalData
+    >
+  ) {
     const orderClaim: OrderClaimDTO = useRemoteQueryStep({
       entry_point: "order_claim",
       fields: [
@@ -157,6 +165,19 @@ export const updateClaimShippingMethodWorkflow = createWorkflow(
       list: false,
     }).config({ name: "order-change-query" })
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        order_claim: orderClaim,
+        order_change: orderChange,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+    const setPricingContextResult = setPricingContext.getResult()
+
     const shippingOptions = when({ input }, ({ input }) => {
       return input.data?.custom_amount === null
     }).then(() => {
@@ -174,6 +195,18 @@ export const updateClaimShippingMethodWorkflow = createWorkflow(
         }
       )
 
+      const pricingContext = transform(
+        { action, setPricingContextResult },
+        (data) => {
+          return {
+            ...(data.setPricingContextResult
+              ? data.setPricingContextResult
+              : {}),
+            currency_code: data.action.currency_code,
+          }
+        }
+      )
+
       const shippingMethod = useRemoteQueryStep({
         entry_point: "order_shipping_method",
         fields: ["id", "shipping_option_id"],
@@ -194,7 +227,7 @@ export const updateClaimShippingMethodWorkflow = createWorkflow(
         variables: {
           id: shippingMethod.shipping_option_id,
           calculated_price: {
-            context: { currency_code: action.currency_code },
+            context: pricingContext,
           },
         },
       }).config({ name: "fetch-shipping-option" })
@@ -212,6 +245,11 @@ export const updateClaimShippingMethodWorkflow = createWorkflow(
       updateOrderShippingMethodsStep([updateData.shippingMethod!])
     )
 
-    return new WorkflowResponse(previewOrderChangeStep(orderClaim.order_id))
+    return new WorkflowResponse(
+      previewOrderChangeStep(orderClaim.order_id) as OrderPreviewDTO,
+      {
+        hooks: [setPricingContext] as const,
+      }
+    )
   }
 )
diff --git a/packages/core/core-flows/src/order/workflows/create-order.ts b/packages/core/core-flows/src/order/workflows/create-order.ts
index c2629b7e9ccf9..228408b1df51e 100644
--- a/packages/core/core-flows/src/order/workflows/create-order.ts
+++ b/packages/core/core-flows/src/order/workflows/create-order.ts
@@ -23,6 +23,7 @@ import { useRemoteQueryStep } from "../../common"
 import { createOrdersStep } from "../steps"
 import { productVariantsFields } from "../utils/fields"
 import { updateOrderTaxLinesWorkflow } from "./update-tax-lines"
+import { pricingContextResult } from "../../cart/utils/schemas"
 
 function prepareLineItems(data) {
   const items = (data.input.items ?? []).map((item) => {
@@ -150,15 +151,30 @@ export const createOrderWorkflow = createWorkflow(
       })
     )
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        variantIds,
+        region,
+        customerData,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+    const setPricingContextResult = setPricingContext.getResult()
+
     // TODO: This is on par with the context used in v1.*, but we can be more flexible.
     const pricingContext = transform(
-      { input, region, customerData },
+      { input, region, customerData, setPricingContextResult },
       (data) => {
         if (!data.region) {
           throw new MedusaError(MedusaError.Types.NOT_FOUND, "Region not found")
         }
 
         return {
+          ...(data.setPricingContextResult ? data.setPricingContextResult : {}),
           currency_code: data.input.currency_code ?? data.region.currency_code,
           region_id: data.region.id,
           customer_id: data.customerData.customer?.id,
@@ -222,7 +238,7 @@ export const createOrderWorkflow = createWorkflow(
     })
 
     return new WorkflowResponse(order, {
-      hooks: [orderCreated],
+      hooks: [orderCreated, setPricingContext] as const,
     })
   }
 )
diff --git a/packages/core/core-flows/src/order/workflows/exchange/update-exchange-shipping-method.ts b/packages/core/core-flows/src/order/workflows/exchange/update-exchange-shipping-method.ts
index e1117790812be..0ee1e29112e00 100644
--- a/packages/core/core-flows/src/order/workflows/exchange/update-exchange-shipping-method.ts
+++ b/packages/core/core-flows/src/order/workflows/exchange/update-exchange-shipping-method.ts
@@ -1,4 +1,5 @@
 import {
+  AdditionalData,
   OrderChangeActionDTO,
   OrderChangeDTO,
   OrderExchangeDTO,
@@ -9,6 +10,7 @@ import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
 import {
   WorkflowData,
   WorkflowResponse,
+  createHook,
   createStep,
   createWorkflow,
   parallelize,
@@ -26,6 +28,7 @@ import {
   throwIfOrderChangeIsNotActive,
 } from "../../utils/order-validation"
 import { prepareShippingMethodUpdate } from "../../utils/prepare-shipping-method"
+import { pricingContextResult } from "../../../cart/utils/schemas"
 
 /**
  * The data to validate that an exchange's shipping method can be updated.
@@ -42,7 +45,10 @@ export type UpdateExchangeShippingMethodValidationStepInput = {
   /**
    * The details of the shipping method update.
    */
-  input: Pick<OrderWorkflow.UpdateExchangeShippingMethodWorkflowInput, "exchange_id" | "action_id">
+  input: Pick<
+    OrderWorkflow.UpdateExchangeShippingMethodWorkflowInput,
+    "exchange_id" | "action_id"
+  >
 }
 
 /**
@@ -50,14 +56,14 @@ export type UpdateExchangeShippingMethodValidationStepInput = {
  * If the exchange is canceled, the order change is not active, the shipping method
  * doesn't exist in the exchange, or the action isn't adding a shipping method,
  * the step will throw an error.
- * 
+ *
  * :::note
- * 
+ *
  * You can retrieve an order exchange and order change 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 = updateExchangeShippingMethodValidationStep({
  *   orderChange: {
@@ -109,10 +115,10 @@ export const updateExchangeShippingMethodWorkflowId =
  * This workflow updates an exchange's inbound or outbound shipping method. It's used by the
  * [Update Inbound Shipping Admin API Route](https://docs.medusajs.com/api/admin#exchanges_postexchangesidinboundshippingmethodaction_id)
  * or the [Outbound Inbound Shipping Admin API Route](https://docs.medusajs.com/api/admin#exchanges_postexchangesidoutboundshippingmethodaction_id).
- * 
+ *
  * You can use this workflow within your customizations or your own custom workflows, allowing you to update an exchange's
  * inbound or outbound shipping method in your custom flow.
- * 
+ *
  * @example
  * const { result } = await updateExchangeShippingMethodWorkflow(container)
  * .run({
@@ -124,16 +130,18 @@ export const updateExchangeShippingMethodWorkflowId =
  *     }
  *   }
  * })
- * 
+ *
  * @summary
- * 
+ *
  * Update an exchange's inbound or outbound shipping method.
  */
 export const updateExchangeShippingMethodWorkflow = createWorkflow(
   updateExchangeShippingMethodWorkflowId,
   function (
-    input: WorkflowData<OrderWorkflow.UpdateExchangeShippingMethodWorkflowInput>
-  ): WorkflowResponse<OrderPreviewDTO> {
+    input: WorkflowData<
+      OrderWorkflow.UpdateExchangeShippingMethodWorkflowInput & AdditionalData
+    >
+  ) {
     const orderExchange: OrderExchangeDTO = useRemoteQueryStep({
       entry_point: "order_exchange",
       fields: [
@@ -161,6 +169,19 @@ export const updateExchangeShippingMethodWorkflow = createWorkflow(
       list: false,
     }).config({ name: "order-change-query" })
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        order_exchange: orderExchange,
+        order_change: orderChange,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+    const setPricingContextResult = setPricingContext.getResult()
+
     const shippingOptions = when({ input }, ({ input }) => {
       return input.data?.custom_amount === null
     }).then(() => {
@@ -178,6 +199,18 @@ export const updateExchangeShippingMethodWorkflow = createWorkflow(
         }
       )
 
+      const pricingContext = transform(
+        { action, setPricingContextResult },
+        (data) => {
+          return {
+            ...(data.setPricingContextResult
+              ? data.setPricingContextResult
+              : {}),
+            currency_code: data.action.currency_code,
+          }
+        }
+      )
+
       const shippingMethod = useRemoteQueryStep({
         entry_point: "order_shipping_method",
         fields: ["id", "shipping_option_id"],
@@ -198,7 +231,7 @@ export const updateExchangeShippingMethodWorkflow = createWorkflow(
         variables: {
           id: shippingMethod.shipping_option_id,
           calculated_price: {
-            context: { currency_code: action.currency_code },
+            context: pricingContext,
           },
         },
       }).config({ name: "fetch-shipping-option" })
@@ -220,6 +253,11 @@ export const updateExchangeShippingMethodWorkflow = createWorkflow(
       updateOrderShippingMethodsStep([updateData.shippingMethod!])
     )
 
-    return new WorkflowResponse(previewOrderChangeStep(orderExchange.order_id))
+    return new WorkflowResponse(
+      previewOrderChangeStep(orderExchange.order_id) as OrderPreviewDTO,
+      {
+        hooks: [setPricingContext] as const,
+      }
+    )
   }
 )
diff --git a/packages/core/core-flows/src/order/workflows/order-edit/create-order-edit-shipping-method.ts b/packages/core/core-flows/src/order/workflows/order-edit/create-order-edit-shipping-method.ts
index 0dbd73e6eb43f..1b40696def3d1 100644
--- a/packages/core/core-flows/src/order/workflows/order-edit/create-order-edit-shipping-method.ts
+++ b/packages/core/core-flows/src/order/workflows/order-edit/create-order-edit-shipping-method.ts
@@ -1,4 +1,5 @@
 import {
+  AdditionalData,
   BigNumberInput,
   OrderChangeDTO,
   OrderDTO,
@@ -7,6 +8,7 @@ import {
 import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
 import {
   WorkflowResponse,
+  createHook,
   createStep,
   createWorkflow,
   transform,
@@ -21,6 +23,7 @@ import {
 import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
 import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
 import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
+import { pricingContextResult } from "../../../cart/utils/schemas"
 
 /**
  * The data to validate that a shipping method can be created for an order edit.
@@ -114,8 +117,8 @@ export const createOrderEditShippingMethodWorkflowId =
 export const createOrderEditShippingMethodWorkflow = createWorkflow(
   createOrderEditShippingMethodWorkflowId,
   function (
-    input: CreateOrderEditShippingMethodWorkflowInput
-  ): WorkflowResponse<OrderPreviewDTO> {
+    input: CreateOrderEditShippingMethodWorkflowInput & AdditionalData
+  ) {
     const order: OrderDTO = useRemoteQueryStep({
       entry_point: "orders",
       fields: ["id", "status", "currency_code", "canceled_at"],
@@ -124,6 +127,29 @@ export const createOrderEditShippingMethodWorkflow = createWorkflow(
       throw_if_key_not_found: true,
     }).config({ name: "order-query" })
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        order,
+        shipping_option_id: input.shipping_option_id,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+    const setPricingContextResult = setPricingContext.getResult()
+
+    const pricingContext = transform(
+      { order, setPricingContextResult },
+      (data) => {
+        return {
+          ...(data.setPricingContextResult ? data.setPricingContextResult : {}),
+          currency_code: data.order.currency_code,
+        }
+      }
+    )
+
     const shippingOptions = useRemoteQueryStep({
       entry_point: "shipping_option",
       fields: [
@@ -135,7 +161,7 @@ export const createOrderEditShippingMethodWorkflow = createWorkflow(
       variables: {
         id: input.shipping_option_id,
         calculated_price: {
-          context: { currency_code: order.currency_code },
+          context: pricingContext,
         },
       },
     }).config({ name: "fetch-shipping-option" })
@@ -213,6 +239,11 @@ export const createOrderEditShippingMethodWorkflow = createWorkflow(
       input: [orderChangeActionInput],
     })
 
-    return new WorkflowResponse(previewOrderChangeStep(order.id))
+    return new WorkflowResponse(
+      previewOrderChangeStep(order.id) as OrderPreviewDTO,
+      {
+        hooks: [setPricingContext] as const,
+      }
+    )
   }
 )
diff --git a/packages/core/core-flows/src/order/workflows/order-edit/update-order-edit-shipping-method.ts b/packages/core/core-flows/src/order/workflows/order-edit/update-order-edit-shipping-method.ts
index 05e2233862643..2a28031188337 100644
--- a/packages/core/core-flows/src/order/workflows/order-edit/update-order-edit-shipping-method.ts
+++ b/packages/core/core-flows/src/order/workflows/order-edit/update-order-edit-shipping-method.ts
@@ -1,4 +1,5 @@
 import {
+  AdditionalData,
   OrderChangeActionDTO,
   OrderChangeDTO,
   OrderDTO,
@@ -9,6 +10,7 @@ import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
 import {
   WorkflowData,
   WorkflowResponse,
+  createHook,
   createStep,
   createWorkflow,
   parallelize,
@@ -23,6 +25,7 @@ import {
 import { previewOrderChangeStep } from "../../steps/preview-order-change"
 import { throwIfOrderChangeIsNotActive } from "../../utils/order-validation"
 import { prepareShippingMethodUpdate } from "../../utils/prepare-shipping-method"
+import { pricingContextResult } from "../../../cart/utils/schemas"
 
 /**
  * The data to validate that an order edit's shipping method can be updated.
@@ -35,21 +38,24 @@ export type UpdateOrderEditShippingMethodValidationStepInput = {
   /**
    * The details of the shipping method to be updated.
    */
-  input: Pick<OrderWorkflow.UpdateOrderEditShippingMethodWorkflowInput, "order_id" | "action_id">
+  input: Pick<
+    OrderWorkflow.UpdateOrderEditShippingMethodWorkflowInput,
+    "order_id" | "action_id"
+  >
 }
 
 /**
  * This step validates that an order edit's shipping method can be updated.
  * If the order change is not active, the shipping method isn't in the order edit,
  * or the action is not adding a shipping method, the step will throw an error.
- * 
+ *
  * :::note
- * 
+ *
  * You can retrieve an order change 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 = updateOrderEditShippingMethodValidationStep({
  *   orderChange: {
@@ -92,12 +98,12 @@ export const updateOrderEditShippingMethodValidationStep = createStep(
 export const updateOrderEditShippingMethodWorkflowId =
   "update-order-edit-shipping-method"
 /**
- * This workflow updates an order edit's shipping method. It's used by the 
+ * This workflow updates an order edit's shipping method. It's used by the
  * [Update Shipping Method Admin API Route](https://docs.medusajs.com/api/admin#order-edits_postordereditsidshippingmethodaction_id).
- * 
+ *
  * You can use this workflow within your customizations or your own custom workflows, allowing you to update an order edit's shipping method
  * in your custom flow.
- * 
+ *
  * @example
  * const { result } = await updateOrderEditShippingMethodWorkflow(container)
  * .run({
@@ -109,16 +115,18 @@ export const updateOrderEditShippingMethodWorkflowId =
  *     }
  *   }
  * })
- * 
+ *
  * @summary
- * 
+ *
  * Update a shipping method of an order edit.
  */
 export const updateOrderEditShippingMethodWorkflow = createWorkflow(
   updateOrderEditShippingMethodWorkflowId,
   function (
-    input: WorkflowData<OrderWorkflow.UpdateOrderEditShippingMethodWorkflowInput>
-  ): WorkflowResponse<OrderPreviewDTO> {
+    input: WorkflowData<
+      OrderWorkflow.UpdateOrderEditShippingMethodWorkflowInput & AdditionalData
+    >
+  ) {
     const order: OrderDTO = useRemoteQueryStep({
       entry_point: "order_claim",
       fields: ["id", "currency_code"],
@@ -139,6 +147,19 @@ export const updateOrderEditShippingMethodWorkflow = createWorkflow(
       list: false,
     }).config({ name: "order-change-query" })
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        order: order,
+        order_change: orderChange,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+    const setPricingContextResult = setPricingContext.getResult()
+
     const shippingOptions = when({ input }, ({ input }) => {
       return input.data?.custom_amount === null
     }).then(() => {
@@ -156,6 +177,18 @@ export const updateOrderEditShippingMethodWorkflow = createWorkflow(
         }
       )
 
+      const pricingContext = transform(
+        { action, setPricingContextResult },
+        (data) => {
+          return {
+            ...(data.setPricingContextResult
+              ? data.setPricingContextResult
+              : {}),
+            currency_code: data.action.currency_code,
+          }
+        }
+      )
+
       const shippingMethod = useRemoteQueryStep({
         entry_point: "order_shipping_method",
         fields: ["id", "shipping_option_id"],
@@ -176,7 +209,7 @@ export const updateOrderEditShippingMethodWorkflow = createWorkflow(
         variables: {
           id: shippingMethod.shipping_option_id,
           calculated_price: {
-            context: { currency_code: action.currency_code },
+            context: pricingContext,
           },
         },
       }).config({ name: "fetch-shipping-option" })
@@ -197,6 +230,11 @@ export const updateOrderEditShippingMethodWorkflow = createWorkflow(
       updateOrderShippingMethodsStep([updateData.shippingMethod!])
     )
 
-    return new WorkflowResponse(previewOrderChangeStep(input.order_id))
+    return new WorkflowResponse(
+      previewOrderChangeStep(input.order_id) as OrderPreviewDTO,
+      {
+        hooks: [setPricingContext] as const,
+      }
+    )
   }
 )
diff --git a/packages/core/core-flows/src/order/workflows/return/create-complete-return.ts b/packages/core/core-flows/src/order/workflows/return/create-complete-return.ts
index 9532affdfa31d..ebc69471dca91 100644
--- a/packages/core/core-flows/src/order/workflows/return/create-complete-return.ts
+++ b/packages/core/core-flows/src/order/workflows/return/create-complete-return.ts
@@ -7,6 +7,7 @@ import {
   OrderWorkflow,
   ShippingOptionDTO,
   WithCalculatedPrice,
+  AdditionalData,
 } from "@medusajs/framework/types"
 import {
   MathBN,
@@ -18,6 +19,7 @@ import {
 import {
   WorkflowData,
   WorkflowResponse,
+  createHook,
   createStep,
   createWorkflow,
   parallelize,
@@ -36,6 +38,7 @@ import {
   throwIfOrderIsCancelled,
 } from "../../utils/order-validation"
 import { validateReturnReasons } from "../../utils/validate-return-reason"
+import { pricingContextResult } from "../../../cart/utils/schemas"
 
 function prepareShippingMethodData({
   orderId,
@@ -186,6 +189,7 @@ function prepareFulfillmentData({
 function prepareReturnShippingOptionQueryVariables({
   order,
   input,
+  setPricingContextResult,
 }: {
   order: {
     currency_code: string
@@ -194,11 +198,13 @@ function prepareReturnShippingOptionQueryVariables({
   input: {
     return_shipping?: OrderWorkflow.CreateOrderReturnWorkflowInput["return_shipping"]
   }
+  setPricingContextResult?: any
 }) {
   const variables = {
     id: input.return_shipping?.option_id,
     calculated_price: {
       context: {
+        ...(setPricingContextResult ? setPricingContextResult : {}),
         currency_code: order.currency_code,
       },
     },
@@ -309,8 +315,10 @@ export const createAndCompleteReturnOrderWorkflowId =
 export const createAndCompleteReturnOrderWorkflow = createWorkflow(
   createAndCompleteReturnOrderWorkflowId,
   function (
-    input: WorkflowData<OrderWorkflow.CreateOrderReturnWorkflowInput>
-  ): WorkflowResponse<ReturnDTO> {
+    input: WorkflowData<
+      OrderWorkflow.CreateOrderReturnWorkflowInput & AdditionalData
+    >
+  ) {
     const order: OrderDTO = useRemoteQueryStep({
       entry_point: "orders",
       fields: [
@@ -329,8 +337,20 @@ export const createAndCompleteReturnOrderWorkflow = createWorkflow(
 
     createCompleteReturnValidationStep({ order, input })
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        order,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+    const setPricingContextResult = setPricingContext.getResult()
+
     const returnShippingOptionsVariables = transform(
-      { input, order },
+      { input, order, setPricingContextResult },
       prepareReturnShippingOptionQueryVariables
     )
 
@@ -415,6 +435,8 @@ export const createAndCompleteReturnOrderWorkflow = createWorkflow(
       }).config({ name: "emit-return-received-event" })
     )
 
-    return new WorkflowResponse(returnCreated)
+    return new WorkflowResponse(returnCreated as ReturnDTO, {
+      hooks: [setPricingContext] as const,
+    })
   }
 )
diff --git a/packages/core/core-flows/src/order/workflows/return/update-return-shipping-method.ts b/packages/core/core-flows/src/order/workflows/return/update-return-shipping-method.ts
index 0069ffcb23bec..595b5520ab1b5 100644
--- a/packages/core/core-flows/src/order/workflows/return/update-return-shipping-method.ts
+++ b/packages/core/core-flows/src/order/workflows/return/update-return-shipping-method.ts
@@ -1,4 +1,5 @@
 import {
+  AdditionalData,
   OrderChangeActionDTO,
   OrderChangeDTO,
   OrderPreviewDTO,
@@ -9,6 +10,7 @@ import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
 import {
   WorkflowData,
   WorkflowResponse,
+  createHook,
   createStep,
   createWorkflow,
   parallelize,
@@ -26,6 +28,7 @@ import {
   throwIfOrderChangeIsNotActive,
 } from "../../utils/order-validation"
 import { prepareShippingMethodUpdate } from "../../utils/prepare-shipping-method"
+import { pricingContextResult } from "../../../cart/utils/schemas"
 
 /**
  * The data to validate that a return's shipping method can be updated.
@@ -42,7 +45,10 @@ export type UpdateReturnShippingMethodValidationStepInput = {
   /**
    * The details of updating the shipping method.
    */
-  input: Pick<OrderWorkflow.UpdateReturnShippingMethodWorkflowInput, "return_id" | "action_id">
+  input: Pick<
+    OrderWorkflow.UpdateReturnShippingMethodWorkflowInput,
+    "return_id" | "action_id"
+  >
 }
 
 /**
@@ -50,14 +56,14 @@ export type UpdateReturnShippingMethodValidationStepInput = {
  * If the return is canceled, the order change is not active,
  * the shipping method isn't in the return, or the action isn't adding a shipping method,
  * the step will throw an error.
- * 
+ *
  * :::note
- * 
+ *
  * You can retrieve a return and order change 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 = updateReturnShippingMethodValidationStep({
  *   orderChange: {
@@ -105,10 +111,10 @@ export const updateReturnShippingMethodWorkflowId =
 /**
  * This workflow updates the shipping method of a return. It's used by the
  * [Update Shipping Method Admin API Route](https://docs.medusajs.com/api/admin#returns_postreturnsidshippingmethodaction_id).
- * 
+ *
  * You can use this workflow within your customizations or your own custom workflows, allowing you
  * to update the shipping method of a return in your custom flows.
- * 
+ *
  * @example
  * const { result } = await updateReturnShippingMethodWorkflow(container)
  * .run({
@@ -120,16 +126,18 @@ export const updateReturnShippingMethodWorkflowId =
  *     }
  *   }
  * })
- * 
+ *
  * @summary
- * 
+ *
  * Update the shipping method of a return.
  */
 export const updateReturnShippingMethodWorkflow = createWorkflow(
   updateReturnShippingMethodWorkflowId,
   function (
-    input: WorkflowData<OrderWorkflow.UpdateReturnShippingMethodWorkflowInput>
-  ): WorkflowResponse<OrderPreviewDTO> {
+    input: WorkflowData<
+      OrderWorkflow.UpdateReturnShippingMethodWorkflowInput & AdditionalData
+    >
+  ) {
     const orderReturn: ReturnDTO = useRemoteQueryStep({
       entry_point: "return",
       fields: [
@@ -157,6 +165,19 @@ export const updateReturnShippingMethodWorkflow = createWorkflow(
       list: false,
     }).config({ name: "order-change-query" })
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        order_return: orderReturn,
+        order_change: orderChange,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+    const setPricingContextResult = setPricingContext.getResult()
+
     const shippingOptions = when({ input }, ({ input }) => {
       return input.data?.custom_amount === null
     }).then(() => {
@@ -174,6 +195,18 @@ export const updateReturnShippingMethodWorkflow = createWorkflow(
         }
       )
 
+      const pricingContext = transform(
+        { action, setPricingContextResult },
+        (data) => {
+          return {
+            ...(data.setPricingContextResult
+              ? data.setPricingContextResult
+              : {}),
+            currency_code: data.action.currency_code,
+          }
+        }
+      )
+
       const shippingMethod = useRemoteQueryStep({
         entry_point: "order_shipping_method",
         fields: ["id", "shipping_option_id"],
@@ -194,7 +227,7 @@ export const updateReturnShippingMethodWorkflow = createWorkflow(
         variables: {
           id: shippingMethod.shipping_option_id,
           calculated_price: {
-            context: { currency_code: action.currency_code },
+            context: pricingContext,
           },
         },
       }).config({ name: "fetch-shipping-option" })
@@ -216,6 +249,11 @@ export const updateReturnShippingMethodWorkflow = createWorkflow(
       updateOrderShippingMethodsStep([updateData.shippingMethod!])
     )
 
-    return new WorkflowResponse(previewOrderChangeStep(orderReturn.order_id))
+    return new WorkflowResponse(
+      previewOrderChangeStep(orderReturn.order_id) as OrderPreviewDTO,
+      {
+        hooks: [setPricingContext] as const,
+      }
+    )
   }
 )
diff --git a/packages/core/workflows-sdk/src/utils/composer/create-hook.ts b/packages/core/workflows-sdk/src/utils/composer/create-hook.ts
index f18fde57f89bc..32a3c321a89d6 100644
--- a/packages/core/workflows-sdk/src/utils/composer/create-hook.ts
+++ b/packages/core/workflows-sdk/src/utils/composer/create-hook.ts
@@ -85,6 +85,9 @@ export function createHook<Name extends string, TInvokeInput, TInvokeOutput>(
       if (options.resultValidator) {
         return options.resultValidator.parse(result)
       }
+      if (result === undefined) {
+        return new StepResponse(undefined)
+      }
       return result
     },
     () => void 0


Reviews:
user: login: carlos-r-l-rodrigues
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-18T18:05:42Z
user: login: olivermrbl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T04:58:02Z
user: login: olivermrbl
body: We also need to add these to workflows calculating shipping option prices.

Separately, I believe we missed a workflow `refresh-cart-items.ts`.

Finally, should we add a few tests to ensure it behaves as expected?
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T05:00:44Z
user: login: carlos-r-l-rodrigues
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T18:21:58Z
user: login: olivermrbl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T08:15:22Z
user: login: olivermrbl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T08:15:47Z
user: login: thetutlage
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T09:48:26Z
user: login: thetutlage
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T09:50:02Z
user: login: carlos-r-l-rodrigues
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T09:58:48Z
user: login: olivermrbl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T10:09:00Z
user: login: olivermrbl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T10:11:14Z
user: login: thetutlage
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T10:15:31Z
user: login: thetutlage
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T10:17:08Z
user: login: olivermrbl
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T10:31:15Z
user: login: thetutlage
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T10:36:58Z
user: login: olivermrbl
body: Nice work @thetutlage!

Left a thought, but otherwise LGTM.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T08:52:44Z
user: login: thetutlage
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T09:05:38Z
user: login: thetutlage
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T09:06:34Z
user: login: olivermrbl
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T09:11:41Z

Review comments:
diff_hunk: @@ -73,6 +78,11 @@ export const updateLineItemInCartWorkflow = createWorkflow(
       return [item.variant_id].filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
path: packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts
user: login: olivermrbl
body: question: Should we also hard-code the currency code and region ID here?
created_at: 2025-03-19T04:58:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -627,6 +638,337 @@ medusaIntegrationTestRunner({
           ])
         })
 
+        describe("setPricingContext hook", () => {
+          it("should use context provided by the hook", async () => {
+            const region = await regionModuleService.createRegions({
+              name: "US",
+              currency_code: "usd",
+            })
+
+            const salesChannel = await scModuleService.createSalesChannels({
+              name: "Webshop",
+            })
+
+            const location = await stockLocationModule.createStockLocations({
+              name: "Warehouse",
+            })
+
+            const [product] = await productModule.createProducts([
+              {
+                title: "Test product",
+                variants: [
+                  {
+                    title: "Test variant",
+                  },
+                ],
+              },
+            ])
+
+            const inventoryItem = await inventoryModule.createInventoryItems({
+              sku: "inv-1234",
+            })
+
+            await inventoryModule.createInventoryLevels([
+              {
+                inventory_item_id: inventoryItem.id,
+                location_id: location.id,
+                stocked_quantity: 2,
+                reserved_quantity: 0,
+              },
+            ])
+
+            const priceSet = await pricingModule.createPriceSets({
+              prices: [
+                {
+                  amount: 3000,
+                  currency_code: "usd",
+                },
+              ],
+            })
+
+            await pricingModule.createPricePreferences({
+              attribute: "currency_code",
+              value: "usd",
+              is_tax_inclusive: true,
+            })
+
+            await remoteLink.create([
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.PRICING]: {
+                  price_set_id: priceSet.id,
+                },
+              },
+              {
+                [Modules.SALES_CHANNEL]: {
+                  sales_channel_id: salesChannel.id,
+                },
+                [Modules.STOCK_LOCATION]: {
+                  stock_location_id: location.id,
+                },
+              },
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.INVENTORY]: {
+                  inventory_item_id: inventoryItem.id,
+                },
+              },
+            ])
+
+            setPricingContextHook = function (input) {
+              expect(input.region).toEqual(
+                expect.objectContaining({
+                  id: region.id,
+                })
+              )
+              expect(input.variantIds).toEqual([product.variants[0].id])
+              expect(input.salesChannel).toEqual(
+                expect.objectContaining({
+                  id: salesChannel.id,
+                })
+              )
+              expect(input.customerData).toEqual(
+                expect.objectContaining({
+                  email: "tony@stark.com",
+                })
+              )
+
+              return new StepResponse({
+                unit_price: 100,
+              })
+            }
+
+            /**
+             * Tried jest, but for some reasons it is not able to provide
+             * correct arguments passed to the function
+             */
+            let pricingContext: any
+            const originalFn = pricingModule.listPriceSets.bind(pricingModule)
+            pricingModule.listPriceSets = function () {
+              pricingContext = { ...arguments[0].context }
+              return originalFn.bind(pricingModule)(...arguments)
+            }
+
+            const { result } = await createCartWorkflow(appContainer).run({
+              input: {
+                email: "tony@stark.com",
+                currency_code: "usd",
+                region_id: region.id,
+                sales_channel_id: salesChannel.id,
+                items: [
+                  {
+                    variant_id: product.variants[0].id,
+                    quantity: 1,
+                  },
+                ],
+              },
+            })
+
+            setPricingContextHook = undefined
+            pricingModule.listPriceSets = originalFn
+
+            expect(pricingContext).toEqual(
+              expect.objectContaining({
+                unit_price: 100,
+                region_id: region.id,
+                currency_code: "usd",
+              })
+            )
+
+            const cart = await cartModuleService.retrieveCart(result.id, {
+              relations: ["items"],
+            })
+
+            expect(cart).toEqual(
+              expect.objectContaining({
+                currency_code: "usd",
+                email: "tony@stark.com",
+                region_id: region.id,
+                sales_channel_id: salesChannel.id,
+                customer_id: expect.any(String),
+                items: expect.arrayContaining([
+                  expect.objectContaining({
+                    quantity: 1,
+                    unit_price: 3000,
+                    is_tax_inclusive: true,
+                  }),
+                ]),
+              })
+            )
+          })
+
+          it("should not be able to override the 'customer_id', 'region_id', and the 'currency_code' from the setPricingContext hook", async () => {
+            const region = await regionModuleService.createRegions({
+              name: "US",
+              currency_code: "usd",
+            })
+
+            const salesChannel = await scModuleService.createSalesChannels({
+              name: "Webshop",
+            })
+
+            const location = await stockLocationModule.createStockLocations({
+              name: "Warehouse",
+            })
+
+            const [product] = await productModule.createProducts([
+              {
+                title: "Test product",
+                variants: [
+                  {
+                    title: "Test variant",
+                  },
+                ],
+              },
+            ])
+
+            const inventoryItem = await inventoryModule.createInventoryItems({
+              sku: "inv-1234",
+            })
+
+            await inventoryModule.createInventoryLevels([
+              {
+                inventory_item_id: inventoryItem.id,
+                location_id: location.id,
+                stocked_quantity: 2,
+                reserved_quantity: 0,
+              },
+            ])
+
+            const priceSet = await pricingModule.createPriceSets({
+              prices: [
+                {
+                  amount: 3000,
+                  currency_code: "usd",
+                },
+              ],
+            })
+
+            await pricingModule.createPricePreferences({
+              attribute: "currency_code",
+              value: "usd",
+              is_tax_inclusive: true,
+            })
+
+            await remoteLink.create([
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.PRICING]: {
+                  price_set_id: priceSet.id,
+                },
+              },
+              {
+                [Modules.SALES_CHANNEL]: {
+                  sales_channel_id: salesChannel.id,
+                },
+                [Modules.STOCK_LOCATION]: {
+                  stock_location_id: location.id,
+                },
+              },
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.INVENTORY]: {
+                  inventory_item_id: inventoryItem.id,
+                },
+              },
+            ])
+
+            setPricingContextHook = function (input) {
+              expect(input.region).toEqual(
+                expect.objectContaining({
+                  id: region.id,
+                })
+              )
+              expect(input.variantIds).toEqual([product.variants[0].id])
+              expect(input.salesChannel).toEqual(
+                expect.objectContaining({
+                  id: salesChannel.id,
+                })
+              )
+              expect(input.customerData).toEqual(
+                expect.objectContaining({
+                  email: "tony@stark.com",
+                })
+              )
+
+              return new StepResponse({
+                unit_price: 200,
+                currency_code: "inr",
+                customer_id: "1",
+                region_id: "1",
+              })
+            }
+
+            /**
+             * Tried jest, but for some reasons it is not able to provide
+             * correct arguments passed to the function
+             */
+            let pricingContext: any
+            const originalFn = pricingModule.listPriceSets.bind(pricingModule)
+            pricingModule.listPriceSets = function () {
+              pricingContext = { ...arguments[0].context }
+              return originalFn.bind(pricingModule)(...arguments)
+            }
+
+            const { result } = await createCartWorkflow(appContainer).run({
+              input: {
+                email: "tony@stark.com",
+                currency_code: "usd",
+                region_id: region.id,
+                sales_channel_id: salesChannel.id,
+                items: [
+                  {
+                    variant_id: product.variants[0].id,
+                    quantity: 1,
+                  },
+                ],
+              },
+            })
+
+            setPricingContextHook = undefined
+            pricingModule.listPriceSets = originalFn
+
+            expect(pricingContext).toEqual(
+              expect.objectContaining({
+                unit_price: 200,
+                region_id: region.id,
+                currency_code: "usd",
path: integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts
user: login: carlos-r-l-rodrigues
body: should we also add `customer_id` on the check?
created_at: 2025-03-26T18:10:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -93,6 +94,24 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
+      variantIds,
+      items: input.items,
+      additional_data: input.additional_data,
+    })
+
+    const setPricingContextResult = setPricingContext.getResult() as any
+    const pricingContext = transform(
+      { cart, setPricingContextResult },
+      (data) => {
+        return {
+          ...data.cart,
path: packages/core/core-flows/src/cart/workflows/add-to-cart.ts
user: login: carlos-r-l-rodrigues
body: I know this was like that before, but maybe we shouldn't pass the entire cart to the pricing module.
We can just use the same fields we are passing on other workflows. 
Apparently there is a util `filterObjectByKeys(data.cart, cartFieldsForPricingContext)` used on other places.

created_at: 2025-03-26T18:15:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -122,7 +137,12 @@ export const listShippingOptionsForCartWorkflow = createWorkflow(
             },
           },
 
-          calculated_price: { context: cart },
+          calculated_price: {
+            context: {
+              ...cart,
path: packages/core/core-flows/src/cart/workflows/list-shipping-options-for-cart.ts
user: login: carlos-r-l-rodrigues
body: same comment as above
created_at: 2025-03-26T18:16:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -93,6 +94,24 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
+      variantIds,
+      items: input.items,
+      additional_data: input.additional_data,
+    })
+
+    const setPricingContextResult = setPricingContext.getResult() as any
path: packages/core/core-flows/src/cart/workflows/add-to-cart.ts
user: login: olivermrbl
body: question: What would it take to get rid of `as any`?
created_at: 2025-03-27T08:15:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -93,6 +94,24 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
+      variantIds,
+      items: input.items,
+      additional_data: input.additional_data,
+    })
+
+    const setPricingContextResult = setPricingContext.getResult() as any
path: packages/core/core-flows/src/cart/workflows/add-to-cart.ts
user: login: olivermrbl
body: This is not super important right now, but I was just curious.
created_at: 2025-03-27T08:15:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -93,6 +94,24 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
+      variantIds,
+      items: input.items,
+      additional_data: input.additional_data,
+    })
+
+    const setPricingContextResult = setPricingContext.getResult() as any
path: packages/core/core-flows/src/cart/workflows/add-to-cart.ts
user: login: thetutlage
body: We will have to settle on the properties the hook must/can return and then define a zod schema to validate those properties. 
created_at: 2025-03-27T09:48:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -93,6 +94,24 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
+      variantIds,
+      items: input.items,
+      additional_data: input.additional_data,
+    })
+
+    const setPricingContextResult = setPricingContext.getResult() as any
+    const pricingContext = transform(
+      { cart, setPricingContextResult },
+      (data) => {
+        return {
+          ...data.cart,
path: packages/core/core-flows/src/cart/workflows/add-to-cart.ts
user: login: thetutlage
body: So essentially all these workflows should send the same set of properties? Which are

- currency_code
- region_id
- customer_id

Do you think there could be an unintentional breaking change after this? 
created_at: 2025-03-27T09:50:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -93,6 +94,24 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
+      variantIds,
+      items: input.items,
+      additional_data: input.additional_data,
+    })
+
+    const setPricingContextResult = setPricingContext.getResult() as any
+    const pricingContext = transform(
+      { cart, setPricingContextResult },
+      (data) => {
+        return {
+          ...data.cart,
path: packages/core/core-flows/src/cart/workflows/add-to-cart.ts
user: login: carlos-r-l-rodrigues
body: There is a bit more that is passed apparently, including shipping address. basically everything that is declared on that variable `cartFieldsForPricingContext`.

Yes, this is unintentional breaking change, but I don't expect that to be widely used. 
@oli can decide here what is the best to be done. I believe the entire cart can be a huge parameter to be passing all the time, but if we want to avoid even this minimal breaking change, ideally all the other places also receive the full cart.
created_at: 2025-03-27T09:58:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -93,6 +94,24 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
+      variantIds,
+      items: input.items,
+      additional_data: input.additional_data,
+    })
+
+    const setPricingContextResult = setPricingContext.getResult() as any
path: packages/core/core-flows/src/cart/workflows/add-to-cart.ts
user: login: olivermrbl
body: Ah I see, should we set it to a record then? So we can get rid of the `any`
created_at: 2025-03-27T10:09:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -93,6 +94,24 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
+      variantIds,
+      items: input.items,
+      additional_data: input.additional_data,
+    })
+
+    const setPricingContextResult = setPricingContext.getResult() as any
+    const pricingContext = transform(
+      { cart, setPricingContextResult },
+      (data) => {
+        return {
+          ...data.cart,
path: packages/core/core-flows/src/cart/workflows/add-to-cart.ts
user: login: olivermrbl
body: @thetutlage @carlos-r-l-rodrigues, should we perhaps leave a TODO that we can revisit when we can be more strict about what we pass in the pricing context? I'd like to avoid having to decide on this right now AND avoid the breaking change.
created_at: 2025-03-27T10:11:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -93,6 +94,24 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
+      variantIds,
+      items: input.items,
+      additional_data: input.additional_data,
+    })
+
+    const setPricingContextResult = setPricingContext.getResult() as any
path: packages/core/core-flows/src/cart/workflows/add-to-cart.ts
user: login: thetutlage
body: Sure
created_at: 2025-03-27T10:15:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -93,6 +94,24 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
+      variantIds,
+      items: input.items,
+      additional_data: input.additional_data,
+    })
+
+    const setPricingContextResult = setPricingContext.getResult() as any
+    const pricingContext = transform(
+      { cart, setPricingContextResult },
+      (data) => {
+        return {
+          ...data.cart,
path: packages/core/core-flows/src/cart/workflows/add-to-cart.ts
user: login: thetutlage
body: Yeah, I tried cherry picking the fields and tests started to fail. Ofcourse, I would have missed some, but I can imagine it being an exercise to find which precise data (per workflow) has to be passed down
created_at: 2025-03-27T10:17:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -93,6 +94,24 @@ export const addToCartWorkflow = createWorkflow(
       return (data.input.items ?? []).map((i) => i.variant_id).filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
+      variantIds,
+      items: input.items,
+      additional_data: input.additional_data,
+    })
+
+    const setPricingContextResult = setPricingContext.getResult() as any
+    const pricingContext = transform(
+      { cart, setPricingContextResult },
+      (data) => {
+        return {
+          ...data.cart,
path: packages/core/core-flows/src/cart/workflows/add-to-cart.ts
user: login: olivermrbl
body: Yeah my thinking too
created_at: 2025-03-27T10:31:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -627,6 +638,337 @@ medusaIntegrationTestRunner({
           ])
         })
 
+        describe("setPricingContext hook", () => {
+          it("should use context provided by the hook", async () => {
+            const region = await regionModuleService.createRegions({
+              name: "US",
+              currency_code: "usd",
+            })
+
+            const salesChannel = await scModuleService.createSalesChannels({
+              name: "Webshop",
+            })
+
+            const location = await stockLocationModule.createStockLocations({
+              name: "Warehouse",
+            })
+
+            const [product] = await productModule.createProducts([
+              {
+                title: "Test product",
+                variants: [
+                  {
+                    title: "Test variant",
+                  },
+                ],
+              },
+            ])
+
+            const inventoryItem = await inventoryModule.createInventoryItems({
+              sku: "inv-1234",
+            })
+
+            await inventoryModule.createInventoryLevels([
+              {
+                inventory_item_id: inventoryItem.id,
+                location_id: location.id,
+                stocked_quantity: 2,
+                reserved_quantity: 0,
+              },
+            ])
+
+            const priceSet = await pricingModule.createPriceSets({
+              prices: [
+                {
+                  amount: 3000,
+                  currency_code: "usd",
+                },
+              ],
+            })
+
+            await pricingModule.createPricePreferences({
+              attribute: "currency_code",
+              value: "usd",
+              is_tax_inclusive: true,
+            })
+
+            await remoteLink.create([
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.PRICING]: {
+                  price_set_id: priceSet.id,
+                },
+              },
+              {
+                [Modules.SALES_CHANNEL]: {
+                  sales_channel_id: salesChannel.id,
+                },
+                [Modules.STOCK_LOCATION]: {
+                  stock_location_id: location.id,
+                },
+              },
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.INVENTORY]: {
+                  inventory_item_id: inventoryItem.id,
+                },
+              },
+            ])
+
+            setPricingContextHook = function (input) {
+              expect(input.region).toEqual(
+                expect.objectContaining({
+                  id: region.id,
+                })
+              )
+              expect(input.variantIds).toEqual([product.variants[0].id])
+              expect(input.salesChannel).toEqual(
+                expect.objectContaining({
+                  id: salesChannel.id,
+                })
+              )
+              expect(input.customerData).toEqual(
+                expect.objectContaining({
+                  email: "tony@stark.com",
+                })
+              )
+
+              return new StepResponse({
+                unit_price: 100,
+              })
+            }
+
+            /**
+             * Tried jest, but for some reasons it is not able to provide
+             * correct arguments passed to the function
+             */
+            let pricingContext: any
+            const originalFn = pricingModule.listPriceSets.bind(pricingModule)
+            pricingModule.listPriceSets = function () {
+              pricingContext = { ...arguments[0].context }
+              return originalFn.bind(pricingModule)(...arguments)
+            }
+
+            const { result } = await createCartWorkflow(appContainer).run({
+              input: {
+                email: "tony@stark.com",
+                currency_code: "usd",
+                region_id: region.id,
+                sales_channel_id: salesChannel.id,
+                items: [
+                  {
+                    variant_id: product.variants[0].id,
+                    quantity: 1,
+                  },
+                ],
+              },
+            })
+
+            setPricingContextHook = undefined
+            pricingModule.listPriceSets = originalFn
+
+            expect(pricingContext).toEqual(
+              expect.objectContaining({
+                unit_price: 100,
+                region_id: region.id,
+                currency_code: "usd",
+              })
+            )
+
+            const cart = await cartModuleService.retrieveCart(result.id, {
+              relations: ["items"],
+            })
+
+            expect(cart).toEqual(
+              expect.objectContaining({
+                currency_code: "usd",
+                email: "tony@stark.com",
+                region_id: region.id,
+                sales_channel_id: salesChannel.id,
+                customer_id: expect.any(String),
+                items: expect.arrayContaining([
+                  expect.objectContaining({
+                    quantity: 1,
+                    unit_price: 3000,
+                    is_tax_inclusive: true,
+                  }),
+                ]),
+              })
+            )
+          })
+
+          it("should not be able to override the 'customer_id', 'region_id', and the 'currency_code' from the setPricingContext hook", async () => {
+            const region = await regionModuleService.createRegions({
+              name: "US",
+              currency_code: "usd",
+            })
+
+            const salesChannel = await scModuleService.createSalesChannels({
+              name: "Webshop",
+            })
+
+            const location = await stockLocationModule.createStockLocations({
+              name: "Warehouse",
+            })
+
+            const [product] = await productModule.createProducts([
+              {
+                title: "Test product",
+                variants: [
+                  {
+                    title: "Test variant",
+                  },
+                ],
+              },
+            ])
+
+            const inventoryItem = await inventoryModule.createInventoryItems({
+              sku: "inv-1234",
+            })
+
+            await inventoryModule.createInventoryLevels([
+              {
+                inventory_item_id: inventoryItem.id,
+                location_id: location.id,
+                stocked_quantity: 2,
+                reserved_quantity: 0,
+              },
+            ])
+
+            const priceSet = await pricingModule.createPriceSets({
+              prices: [
+                {
+                  amount: 3000,
+                  currency_code: "usd",
+                },
+              ],
+            })
+
+            await pricingModule.createPricePreferences({
+              attribute: "currency_code",
+              value: "usd",
+              is_tax_inclusive: true,
+            })
+
+            await remoteLink.create([
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.PRICING]: {
+                  price_set_id: priceSet.id,
+                },
+              },
+              {
+                [Modules.SALES_CHANNEL]: {
+                  sales_channel_id: salesChannel.id,
+                },
+                [Modules.STOCK_LOCATION]: {
+                  stock_location_id: location.id,
+                },
+              },
+              {
+                [Modules.PRODUCT]: {
+                  variant_id: product.variants[0].id,
+                },
+                [Modules.INVENTORY]: {
+                  inventory_item_id: inventoryItem.id,
+                },
+              },
+            ])
+
+            setPricingContextHook = function (input) {
+              expect(input.region).toEqual(
+                expect.objectContaining({
+                  id: region.id,
+                })
+              )
+              expect(input.variantIds).toEqual([product.variants[0].id])
+              expect(input.salesChannel).toEqual(
+                expect.objectContaining({
+                  id: salesChannel.id,
+                })
+              )
+              expect(input.customerData).toEqual(
+                expect.objectContaining({
+                  email: "tony@stark.com",
+                })
+              )
+
+              return new StepResponse({
+                unit_price: 200,
+                currency_code: "inr",
+                customer_id: "1",
+                region_id: "1",
+              })
+            }
+
+            /**
+             * Tried jest, but for some reasons it is not able to provide
+             * correct arguments passed to the function
+             */
+            let pricingContext: any
+            const originalFn = pricingModule.listPriceSets.bind(pricingModule)
+            pricingModule.listPriceSets = function () {
+              pricingContext = { ...arguments[0].context }
+              return originalFn.bind(pricingModule)(...arguments)
+            }
+
+            const { result } = await createCartWorkflow(appContainer).run({
+              input: {
+                email: "tony@stark.com",
+                currency_code: "usd",
+                region_id: region.id,
+                sales_channel_id: salesChannel.id,
+                items: [
+                  {
+                    variant_id: product.variants[0].id,
+                    quantity: 1,
+                  },
+                ],
+              },
+            })
+
+            setPricingContextHook = undefined
+            pricingModule.listPriceSets = originalFn
+
+            expect(pricingContext).toEqual(
+              expect.objectContaining({
+                unit_price: 200,
+                region_id: region.id,
+                currency_code: "usd",
path: integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts
user: login: thetutlage
body: Just realized, that check is here. https://github.com/medusajs/medusa/pull/11891/files#diff-3084247c8dbb6a88ec078934d653e7c0e243bd1f59a2d7f982e94c451f2bcffaR947

This is because I do not have the customer_id handy. Its pulled under the hood from the email
created_at: 2025-03-27T10:36:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -73,6 +79,30 @@ export const updateLineItemInCartWorkflow = createWorkflow(
       return [item.variant_id].filter(Boolean)
     })
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        cart,
+        item,
+        variantIds,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+
+    const setPricingContextResult = setPricingContext.getResult()
+    const pricingContext = transform(
+      { cart, setPricingContextResult },
+      (data) => {
+        return {
+          ...data.cart,
+          ...(data.setPricingContextResult ? data.setPricingContextResult : {}),
path: packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts
user: login: olivermrbl
body: suggestion: I wonder if we should enforce currency, region, and customer here? Now that we are opening up for extensibility, users could mistakenly overwrite those. We probably don't want that to happen.

**Same thought for all cart workflows.**
created_at: 2025-03-28T08:52:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -73,6 +78,11 @@ export const updateLineItemInCartWorkflow = createWorkflow(
       return [item.variant_id].filter(Boolean)
     })
 
+    const setPricingContext = createHook("setPricingContext", {
+      cart,
path: packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts
user: login: thetutlage
body: Done
created_at: 2025-03-28T09:05:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -73,6 +79,30 @@ export const updateLineItemInCartWorkflow = createWorkflow(
       return [item.variant_id].filter(Boolean)
     })
 
+    const setPricingContext = createHook(
+      "setPricingContext",
+      {
+        cart,
+        item,
+        variantIds,
+        additional_data: input.additional_data,
+      },
+      {
+        resultValidator: pricingContextResult,
+      }
+    )
+
+    const setPricingContextResult = setPricingContext.getResult()
+    const pricingContext = transform(
+      { cart, setPricingContextResult },
+      (data) => {
+        return {
+          ...data.cart,
+          ...(data.setPricingContextResult ? data.setPricingContextResult : {}),
path: packages/core/core-flows/src/cart/workflows/update-line-item-in-cart.ts
user: login: thetutlage
body: Yup, fixed all those with tests. https://github.com/medusajs/medusa/pull/11891/commits/279d2fa5e86bc37aea796f8118b5f4a8639132ad
created_at: 2025-03-28T09:06:34Z
author_association: CONTRIBUTOR

PR comments:
user: login: vercel[bot]
created_at: 2025-03-18T11:29:02Z
body: [vc]: #d+d1SpsRkRE9ekyM38NIp9QCaapf0vA156hnza+gfUs=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJtZWR1c2EtZGFzaGJvYXJkIiwicm9vdERpcmVjdG9yeSI6InBhY2thZ2VzL2FkbWluL2Rhc2hib2FyZCIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9tZWR1c2Fqcy9tZWR1c2EtZGFzaGJvYXJkL0NwZzJteE0zZ3c1VmF6b0xuUnFSczc1V0VyNWQiLCJwcmV2aWV3VXJsIjoibWVkdXNhLWRhc2hib2FyZC1naXQtZmVhdC1zZXQtcHJpY2luZy1jb250ZXh0LWhvb2stbWVkdXNhanMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJERVBMT1lFRCIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJtZWR1c2EtZGFzaGJvYXJkLWdpdC1mZWF0LXNldC1wcmljaW5nLWNvbnRleHQtaG9vay1tZWR1c2Fqcy52ZXJjZWwuYXBwIn19LHsibmFtZSI6ImFwaS1yZWZlcmVuY2UtdjIiLCJyb290RGlyZWN0b3J5Ijoid3d3L2FwcHMvYXBpLXJlZmVyZW5jZSIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9tZWR1c2Fqcy9hcGktcmVmZXJlbmNlLXYyL0NRUmZOV3N6QWV0ODhaREo1Nld4dHhqQlEzalYiLCJwcmV2aWV3VXJsIjoiYXBpLXJlZmVyZW5jZS12Mi1naXQtZmVhdC1zZXQtcHJpY2luZy1jb250ZXh0LWhvb2stbWVkdXNhanMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJJR05PUkVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6IiJ9fSx7Im5hbWUiOiJtZWR1c2EtZG9jcyIsInJvb3REaXJlY3RvcnkiOiJ3d3cvYXBwcy9kb2NzIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL21lZHVzYWpzL21lZHVzYS1kb2NzL0s1bk1QckM1eEp5WnJxbUp2NXZjNzlrZTlndUIiLCJwcmV2aWV3VXJsIjoibWVkdXNhLWRvY3MtZ2l0LWZlYXQtc2V0LXByaWNpbmctY29udGV4dC1ob29rLW1lZHVzYWpzLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiSUdOT1JFRCIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiIifX0seyJuYW1lIjoiYXBpLXJlZmVyZW5jZSIsInJvb3REaXJlY3RvcnkiOiJ3d3cvYXBwcy9hcGktcmVmZXJlbmNlIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL21lZHVzYWpzL2FwaS1yZWZlcmVuY2UvQ1k5WEtSVG1vdVJtNWgzNkxrN3V6c2FuN29iMiIsInByZXZpZXdVcmwiOiJhcGktcmVmZXJlbmNlLWdpdC1mZWF0LXNldC1wcmljaW5nLWNvbnRleHQtaG9vay1tZWR1c2Fqcy52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IlBFTkRJTkciLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoiYXBpLXJlZmVyZW5jZS1naXQtZmVhdC1zZXQtcHJpY2luZy1jb250ZXh0LWhvb2stbWVkdXNhanMudmVyY2VsLmFwcCJ9fSx7Im5hbWUiOiJkb2NzLXVpIiwicm9vdERpcmVjdG9yeSI6Ind3dy9hcHBzL3VpIiwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL21lZHVzYWpzL2RvY3MtdWkvN2YxQ25vTThNSGhGc05zMTdmS2FvMnphN3hOWiIsInByZXZpZXdVcmwiOiJkb2NzLXVpLWdpdC1mZWF0LXNldC1wcmljaW5nLWNvbnRleHQtaG9vay1tZWR1c2Fqcy52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IklHTk9SRUQiLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoiIn19LHsibmFtZSI6InJlc291cmNlcy1kb2NzIiwicm9vdERpcmVjdG9yeSI6Ind3dy9hcHBzL3Jlc291cmNlcyIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9tZWR1c2Fqcy9yZXNvdXJjZXMtZG9jcy9DUWFqY3hhYkNnOHkxS25LbXVYazEzYmtOS0ZzIiwicHJldmlld1VybCI6InJlc291cmNlcy1kb2NzLWdpdC1mZWF0LXNldC1wcmljaW5nLWNvbnRleHQtaG9vay1tZWR1c2Fqcy52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IklHTk9SRUQiLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoiIn19LHsibmFtZSI6ImRvY3MtdjIiLCJyb290RGlyZWN0b3J5Ijoid3d3L2FwcHMvYm9vayIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9tZWR1c2Fqcy9kb2NzLXYyLzdnNlF6OU1iQ1R3eVVhZkdlcjRSQThVQk1HYmUiLCJwcmV2aWV3VXJsIjoiZG9jcy12Mi1naXQtZmVhdC1zZXQtcHJpY2luZy1jb250ZXh0LWhvb2stbWVkdXNhanMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJJR05PUkVEIiwibGl2ZUZlZWRiYWNrIjp7InJlc29sdmVkIjowLCJ1bnJlc29sdmVkIjowLCJ0b3RhbCI6MCwibGluayI6IiJ9fSx7Im5hbWUiOiJ1c2VyLWd1aWRlIiwicm9vdERpcmVjdG9yeSI6Ind3dy9hcHBzL3VzZXItZ3VpZGUiLCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vbWVkdXNhanMvdXNlci1ndWlkZS81OEJiWlNNaGFINmJodk5IQlpXZFdOQmZqeUpZIiwicHJldmlld1VybCI6InVzZXItZ3VpZGUtZ2l0LWZlYXQtc2V0LXByaWNpbmctY29udGV4dC1ob29rLW1lZHVzYWpzLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiSUdOT1JFRCIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiIifX1dfQ==
**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/CY9XKRTmouRm5h36Lk7uzsan7ob2)) | [Visit Preview](https://api-reference-git-feat-set-pricing-context-hook-medusajs.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/api-reference-git-feat-set-pricing-context-hook-medusajs.vercel.app?via=pr-comment-feedback-link) | Mar 28, 2025 9:29am |
| **medusa-dashboard** | ✅ Ready ([Inspect](https://vercel.com/medusajs/medusa-dashboard/Cpg2mxM3gw5VazoLnRqRs75WEr5d)) | [Visit Preview](https://medusa-dashboard-git-feat-set-pricing-context-hook-medusajs.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/medusa-dashboard-git-feat-set-pricing-context-hook-medusajs.vercel.app?via=pr-comment-feedback-link) | Mar 28, 2025 9:29am |

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

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **api-reference-v2** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/api-reference-v2/CQRfNWszAet88ZDJ56WxtxjBQ3jV)) | [Visit Preview](https://api-reference-v2-git-feat-set-pricing-context-hook-medusajs.vercel.app) |  | Mar 28, 2025 9:29am |
| **docs-ui** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/docs-ui/7f1CnoM8MHhFsNs17fKao2za7xNZ)) | [Visit Preview](https://docs-ui-git-feat-set-pricing-context-hook-medusajs.vercel.app) |  | Mar 28, 2025 9:29am |
| **docs-v2** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/docs-v2/7g6Qz9MbCTwyUafGer4RA8UBMGbe)) | [Visit Preview](https://docs-v2-git-feat-set-pricing-context-hook-medusajs.vercel.app) |  | Mar 28, 2025 9:29am |
| **medusa-docs** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/medusa-docs/K5nMPrC5xJyZrqmJv5vc79ke9guB)) | [Visit Preview](https://medusa-docs-git-feat-set-pricing-context-hook-medusajs.vercel.app) |  | Mar 28, 2025 9:29am |
| **resources-docs** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/resources-docs/CQajcxabCg8y1KnKmuXk13bkNKFs)) | [Visit Preview](https://resources-docs-git-feat-set-pricing-context-hook-medusajs.vercel.app) |  | Mar 28, 2025 9:29am |
| **user-guide** | ⬜️ Ignored ([Inspect](https://vercel.com/medusajs/user-guide/58BbZSMhaH6bhvNHBZWdWNBfjyJY)) | [Visit Preview](https://user-guide-git-feat-set-pricing-context-hook-medusajs.vercel.app) |  | Mar 28, 2025 9:29am |
</details>









author_association: NONE
user: login: changeset-bot[bot]
created_at: 2025-03-18T11:29:05Z
body: ###  🦋  Changeset detected

Latest commit: 7d08952d0b0975f8141e63b738a1d8b06ead771c

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



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/feat/set-pricing-context-hook?filename=.changeset/funny-birds-live.md&value=---%0A%22%40fake-scope%2Ffake-pkg%22%3A%20patch%0A---%0A%0Afeat%3A%20Set%20pricing%20context%20hook%0A)


author_association: NONE
user: login: thetutlage
created_at: 2025-03-19T06:05:42Z
body: > Finally, should we add a few tests to ensure it behaves as expected?

Testing with hooks is a little tricky, since the hooks are applied globally on all the executions of a workflow. So, if I define a hook that mutates the `pricingContext`, then that mutation will leak into all the tests as well.

@carlos-r-l-rodrigues Do you have any tips on how we can approach testing in this case?
author_association: CONTRIBUTOR