diff --git a/integration-tests/http/__tests__/returns/returns.spec.ts b/integration-tests/http/__tests__/returns/returns.spec.ts index 1e347ec5ac..05b7eafbcf 100644 --- a/integration-tests/http/__tests__/returns/returns.spec.ts +++ b/integration-tests/http/__tests__/returns/returns.spec.ts @@ -202,27 +202,17 @@ medusaIntegrationTestRunner({ adminHeaders ) + await api.post( + `/admin/stock-locations/${location.id}/fulfillment-providers`, + { add: ["manual_test-provider"] }, + adminHeaders + ) + const remoteLink = container.resolve( ContainerRegistrationKeys.REMOTE_LINK ) await remoteLink.create([ - { - [Modules.STOCK_LOCATION]: { - stock_location_id: location.id, - }, - [Modules.FULFILLMENT]: { - fulfillment_set_id: fulfillmentSet.id, - }, - }, - { - [Modules.STOCK_LOCATION]: { - stock_location_id: location.id, - }, - [Modules.FULFILLMENT]: { - fulfillment_provider_id: "manual_test-provider", - }, - }, { [Modules.SALES_CHANNEL]: { sales_channel_id: "test", diff --git a/integration-tests/http/__tests__/shipping-option/admin/shipping-option.spec.ts b/integration-tests/http/__tests__/shipping-option/admin/shipping-option.spec.ts index 88ba47d373..070b4a94f4 100644 --- a/integration-tests/http/__tests__/shipping-option/admin/shipping-option.spec.ts +++ b/integration-tests/http/__tests__/shipping-option/admin/shipping-option.spec.ts @@ -1,8 +1,4 @@ -import { - ContainerRegistrationKeys, - Modules, - RuleOperator, -} from "@medusajs/utils" +import { RuleOperator } from "@medusajs/utils" import { medusaIntegrationTestRunner } from "medusa-test-utils" import { adminHeaders, @@ -65,6 +61,12 @@ medusaIntegrationTestRunner({ ) ).data.stock_location + await api.post( + `/admin/stock-locations/${location.id}/fulfillment-providers`, + { add: ["manual_test-provider"] }, + adminHeaders + ) + fulfillmentSet = ( await api.post( `/admin/fulfillment-sets/${location.fulfillment_sets[0].id}/service-zones`, @@ -111,22 +113,6 @@ medusaIntegrationTestRunner({ }) it("should create a shipping option successfully", async () => { - const remoteLink = appContainer.resolve( - ContainerRegistrationKeys.REMOTE_LINK - ) - - // TODO: move this to an endpoint when available - await remoteLink.create([ - { - [Modules.STOCK_LOCATION]: { - stock_location_id: location.id, - }, - [Modules.FULFILLMENT]: { - fulfillment_provider_id: "manual_test-provider", - }, - }, - ]) - const shippingOptionPayload = { name: "Test shipping option", service_zone_id: fulfillmentSet.service_zones[0].id, @@ -271,22 +257,6 @@ medusaIntegrationTestRunner({ ], } - const remoteLink = appContainer.resolve( - ContainerRegistrationKeys.REMOTE_LINK - ) - - // TODO: move this to an endpoint when available - await remoteLink.create([ - { - [Modules.STOCK_LOCATION]: { - stock_location_id: location.id, - }, - [Modules.FULFILLMENT]: { - fulfillment_provider_id: "manual_test-provider", - }, - }, - ]) - const response = await api.post( `/admin/shipping-options`, shippingOptionPayload, @@ -432,22 +402,6 @@ medusaIntegrationTestRunner({ rules: [shippingOptionRule], } - const remoteLink = appContainer.resolve( - ContainerRegistrationKeys.REMOTE_LINK - ) - - // TODO: move this to an endpoint when available - await remoteLink.create([ - { - [Modules.STOCK_LOCATION]: { - stock_location_id: location.id, - }, - [Modules.FULFILLMENT]: { - fulfillment_provider_id: "manual_test-provider", - }, - }, - ]) - const response = await api.post( `/admin/shipping-options`, shippingOptionPayload, @@ -501,22 +455,6 @@ medusaIntegrationTestRunner({ rules: [shippingOptionRule], } - const remoteLink = appContainer.resolve( - ContainerRegistrationKeys.REMOTE_LINK - ) - - // TODO: move this to an endpoint when available - await remoteLink.create([ - { - [Modules.STOCK_LOCATION]: { - stock_location_id: location.id, - }, - [Modules.FULFILLMENT]: { - fulfillment_provider_id: "manual_test-provider", - }, - }, - ]) - const response = await api.post( `/admin/shipping-options`, shippingOptionPayload, diff --git a/integration-tests/http/__tests__/stock-location/admin/fulfillment-provider.spec.ts b/integration-tests/http/__tests__/stock-location/admin/fulfillment-provider.spec.ts new file mode 100644 index 0000000000..cef71558ab --- /dev/null +++ b/integration-tests/http/__tests__/stock-location/admin/fulfillment-provider.spec.ts @@ -0,0 +1,66 @@ +import { + adminHeaders, + createAdminUser, +} from "../../../../helpers/create-admin-user" + +import { medusaIntegrationTestRunner } from "medusa-test-utils" + +jest.setTimeout(30000) + +medusaIntegrationTestRunner({ + testSuite: ({ dbConnection, getContainer, api }) => { + let location + + beforeEach(async () => { + await createAdminUser(dbConnection, adminHeaders, getContainer()) + + location = ( + await api.post( + `/admin/stock-locations`, + { + name: "Test Location 1", + address: { + address_1: "Test Address", + country_code: "US", + }, + }, + adminHeaders + ) + ).data.stock_location + }) + + describe("POST /admin/stock-locations/:id/fulfillment-providers", () => { + it("should add a fulfillment provider to a stock location successfully", async () => { + const response = await api.post( + `/admin/stock-locations/${location.id}/fulfillment-providers?fields=id,*fulfillment_providers`, + { add: ["manual_test-provider"] }, + adminHeaders + ) + + expect(response.status).toEqual(200) + expect(response.data.stock_location.fulfillment_providers).toEqual([ + { id: "manual_test-provider", is_enabled: true }, + ]) + }) + + it("should detach a fulfillment provider from a stock location successfully", async () => { + await api.post( + `/admin/stock-locations/${location.id}/fulfillment-providers`, + { add: ["manual_test-provider"] }, + adminHeaders + ) + + const response = await api.post( + `/admin/stock-locations/${location.id}/fulfillment-providers?fields=id,*fulfillment_providers`, + { remove: ["manual_test-provider"] }, + adminHeaders + ) + + expect(response.status).toEqual(200) + expect(response.data.stock_location.fulfillment_providers).toHaveLength( + 0 + ) + }) + }) + }, +}) 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 0fd2f1b0e1..9446653d8f 100644 --- a/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts +++ b/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts @@ -1499,16 +1499,11 @@ medusaIntegrationTestRunner({ }, ]) - await remoteLink.create([ - { - [Modules.STOCK_LOCATION]: { - stock_location_id: stockLocation.id, - }, - [Modules.FULFILLMENT]: { - fulfillment_provider_id: "manual_test-provider", - }, - }, - ]) + await api.post( + `/admin/stock-locations/${stockLocation.id}/fulfillment-providers`, + { add: ["manual_test-provider"] }, + adminHeaders + ) const shippingOption = await fulfillmentModule.createShippingOptions({ name: "Test shipping option", diff --git a/integration-tests/modules/__tests__/cart/store/carts.spec.ts b/integration-tests/modules/__tests__/cart/store/carts.spec.ts index 65c18a25b4..f589ff4624 100644 --- a/integration-tests/modules/__tests__/cart/store/carts.spec.ts +++ b/integration-tests/modules/__tests__/cart/store/carts.spec.ts @@ -1941,16 +1941,11 @@ medusaIntegrationTestRunner({ }, ]) - await remoteLink.create([ - { - [Modules.STOCK_LOCATION]: { - stock_location_id: stockLocation.id, - }, - [Modules.FULFILLMENT]: { - fulfillment_provider_id: "manual_test-provider", - }, - }, - ]) + await api.post( + `/admin/stock-locations/${stockLocation.id}/fulfillment-providers`, + { add: ["manual_test-provider"] }, + adminHeaders + ) shippingOption = ( await api.post( diff --git a/integration-tests/modules/__tests__/link-modules/shipping-option-price-set.spec.ts b/integration-tests/modules/__tests__/link-modules/shipping-option-price-set.spec.ts index 2ddfd3fce6..f311844dce 100644 --- a/integration-tests/modules/__tests__/link-modules/shipping-option-price-set.spec.ts +++ b/integration-tests/modules/__tests__/link-modules/shipping-option-price-set.spec.ts @@ -69,16 +69,12 @@ medusaIntegrationTestRunner({ }, ]) - await remoteLink.create([ - { - [Modules.STOCK_LOCATION]: { - stock_location_id: location.id, - }, - [Modules.FULFILLMENT]: { - fulfillment_provider_id: "manual_test-provider", - }, - }, - ]) + await api.post( + `/admin/stock-locations/${location.id}/fulfillment-providers`, + { add: ["manual_test-provider"] }, + adminHeaders + ) + const serviceZone = await fulfillmentModule.createServiceZones({ name: "Test", fulfillment_set_id: fulfillmentSet.id, diff --git a/integration-tests/modules/__tests__/order/workflows/begin-order-claim.spec.ts b/integration-tests/modules/__tests__/order/workflows/begin-order-claim.spec.ts index 8914ac9441..67d7c5c636 100644 --- a/integration-tests/modules/__tests__/order/workflows/begin-order-claim.spec.ts +++ b/integration-tests/modules/__tests__/order/workflows/begin-order-claim.spec.ts @@ -126,9 +126,6 @@ async function prepareDataFixtures({ container }) { fulfillment_provider_id: "manual_test-provider", }, }, - ]) - - await remoteLink.create([ { [Modules.STOCK_LOCATION]: { stock_location_id: location.id, diff --git a/integration-tests/modules/__tests__/shipping-options/store/shipping-options.spec.ts b/integration-tests/modules/__tests__/shipping-options/store/shipping-options.spec.ts index 1bf57af1bd..b7046a1635 100644 --- a/integration-tests/modules/__tests__/shipping-options/store/shipping-options.spec.ts +++ b/integration-tests/modules/__tests__/shipping-options/store/shipping-options.spec.ts @@ -134,16 +134,14 @@ medusaIntegrationTestRunner({ fulfillment_set_id: fulfillmentSet.id, }, }, - { - [Modules.STOCK_LOCATION]: { - stock_location_id: stockLocation.id, - }, - [Modules.FULFILLMENT]: { - fulfillment_provider_id: "manual_test-provider", - }, - }, ]) + await api.post( + `/admin/stock-locations/${stockLocation.id}/fulfillment-providers`, + { add: ["manual_test-provider"] }, + adminHeaders + ) + shippingOption = ( await api.post( `/admin/shipping-options`, diff --git a/packages/core/core-flows/src/common/steps/update-remote-links.ts b/packages/core/core-flows/src/common/steps/update-remote-links.ts index 1354a30b8a..d9c364d317 100644 --- a/packages/core/core-flows/src/common/steps/update-remote-links.ts +++ b/packages/core/core-flows/src/common/steps/update-remote-links.ts @@ -6,7 +6,7 @@ export const updateRemoteLinksStepId = "update-remote-links-step" export const updateRemoteLinksStep = createStep( updateRemoteLinksStepId, async (data: LinkDefinition[], { container }) => { - if (!data.length) { + if (!data?.length) { return new StepResponse([], []) } diff --git a/packages/medusa/src/api/admin/stock-locations/[id]/fulfillment-providers/route.ts b/packages/medusa/src/api/admin/stock-locations/[id]/fulfillment-providers/route.ts new file mode 100644 index 0000000000..12ee9ab1c9 --- /dev/null +++ b/packages/medusa/src/api/admin/stock-locations/[id]/fulfillment-providers/route.ts @@ -0,0 +1,41 @@ +import { batchLinksWorkflow } from "@medusajs/core-flows" +import { LinkMethodRequest } from "@medusajs/types" +import { Modules } from "@medusajs/utils" + +import { + AuthenticatedMedusaRequest, + MedusaResponse, +} from "../../../../../types/routing" +import { refetchStockLocation } from "../../helpers" + +const buildLinks = (id, fulfillmentProviderIds: string[]) => { + return fulfillmentProviderIds.map((fulfillmentProviderId) => ({ + [Modules.STOCK_LOCATION]: { stock_location_id: id }, + [Modules.FULFILLMENT]: { + fulfillment_provider_id: fulfillmentProviderId, + }, + })) +} + +export const POST = async ( + req: AuthenticatedMedusaRequest, + res: MedusaResponse +) => { + const { id } = req.params + const { add = [], remove = [] } = req.validatedBody + + await batchLinksWorkflow(req.scope).run({ + input: { + create: buildLinks(id, add), + delete: buildLinks(id, remove), + }, + }) + + const stockLocation = await refetchStockLocation( + req.params.id, + req.scope, + req.remoteQueryConfig.fields + ) + + res.status(200).json({ stock_location: stockLocation }) +} diff --git a/packages/medusa/src/api/admin/stock-locations/middlewares.ts b/packages/medusa/src/api/admin/stock-locations/middlewares.ts index e988594ccb..607787f78a 100644 --- a/packages/medusa/src/api/admin/stock-locations/middlewares.ts +++ b/packages/medusa/src/api/admin/stock-locations/middlewares.ts @@ -82,4 +82,15 @@ export const adminStockLocationRoutesMiddlewares: MiddlewareRoute[] = [ ), ], }, + { + method: ["POST"], + matcher: "/admin/stock-locations/:id/fulfillment-providers", + middlewares: [ + validateAndTransformBody(createLinkBody()), + validateAndTransformQuery( + AdminGetStockLocationParams, + QueryConfig.retrieveTransformQueryConfig + ), + ], + }, ]