From e944a627f074fb39a56f4bc7b3d6d315736ebf7c Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Thu, 4 Apr 2024 20:41:34 +0200 Subject: [PATCH] feat: region payment providers management workflows/api (#6864) --- .changeset/few-plants-float.md | 13 ++ .../region-payment-provider.spec.ts | 11 +- .../__tests__/regions/admin/regions.spec.ts | 175 +++++++++++++- .../regions/workflows/create-region.spec.ts | 148 ++++++++++++ .../regions/workflows/update-region.spec.ts | 112 +++++++++ integration-tests/modules/medusa-config.js | 19 +- .../steps/set-regions-payment-providers.ts | 216 ++++++++++++++++++ .../src/region/steps/update-regions.ts | 6 +- .../src/region/workflows/create-regions.ts | 56 ++++- .../src/region/workflows/update-regions.ts | 52 +++-- .../definitions/cart-payment-collection.ts | 2 +- .../src/definitions/cart-promotion.ts | 2 +- .../definitions/fulfillment-set-location.ts | 2 +- .../src/definitions/order-sales-channel.ts | 3 +- .../src/definitions/product-sales-channel.ts | 2 +- .../definitions/product-shipping-profile.ts | 2 +- .../product-variant-inventory-item.ts | 2 +- .../definitions/product-variant-price-set.ts | 2 +- .../publishable-api-key-sales-channel.ts | 2 +- .../definitions/region-payment-provider.ts | 2 +- .../src/definitions/sales-channel-location.ts | 2 +- .../definitions/shipping-option-price-set.ts | 2 +- .../src/medusa-test-runner.ts | 6 +- .../src/module-test-runner.ts | 2 +- .../src/api-v2/admin/regions/[id]/route.ts | 22 +- .../src/api-v2/admin/regions/middlewares.ts | 16 +- .../src/api-v2/admin/regions/query-config.ts | 7 +- .../medusa/src/api-v2/admin/regions/route.ts | 30 ++- .../src/api-v2/admin/regions/validators.ts | 12 +- packages/modules-sdk/src/definitions.ts | 1 + packages/orchestration/src/joiner/helpers.ts | 6 +- packages/payment/src/index.ts | 1 + packages/payment/src/types/index.ts | 24 +- packages/types/src/payment/common.ts | 2 +- packages/types/src/region/common.ts | 2 +- packages/types/src/workflow/index.ts | 1 + .../src/workflow/region/create-regions.ts | 9 + packages/types/src/workflow/region/index.ts | 2 + .../src/workflow/region/update-regions.ts | 10 + packages/utils/src/bundles.ts | 1 + .../remote-query-object-from-string.spec.ts | 51 +++++ .../common/remote-query-object-from-string.ts | 43 ++-- packages/utils/src/index.ts | 1 + packages/utils/src/link/compose-link-name.ts | 9 + packages/utils/src/link/index.ts | 2 + .../src => utils/src/link}/links.ts | 4 +- packages/utils/src/modules-sdk/definition.ts | 24 ++ packages/utils/src/modules-sdk/index.ts | 1 + 48 files changed, 1033 insertions(+), 89 deletions(-) create mode 100644 .changeset/few-plants-float.md create mode 100644 integration-tests/modules/__tests__/regions/workflows/create-region.spec.ts create mode 100644 integration-tests/modules/__tests__/regions/workflows/update-region.spec.ts create mode 100644 packages/core-flows/src/region/steps/set-regions-payment-providers.ts create mode 100644 packages/types/src/workflow/region/create-regions.ts create mode 100644 packages/types/src/workflow/region/index.ts create mode 100644 packages/types/src/workflow/region/update-regions.ts create mode 100644 packages/utils/src/link/compose-link-name.ts create mode 100644 packages/utils/src/link/index.ts rename packages/{link-modules/src => utils/src/link}/links.ts (94%) create mode 100644 packages/utils/src/modules-sdk/definition.ts diff --git a/.changeset/few-plants-float.md b/.changeset/few-plants-float.md new file mode 100644 index 0000000000..8c8d0c9512 --- /dev/null +++ b/.changeset/few-plants-float.md @@ -0,0 +1,13 @@ +--- +"@medusajs/medusa": patch +"@medusajs/core-flows": patch +"@medusajs/link-modules": patch +"medusa-test-utils": patch +"@medusajs/modules-sdk": patch +"@medusajs/orchestration": patch +"@medusajs/payment": patch +"@medusajs/types": patch +"@medusajs/utils": patch +--- + +feat: region payment providers management workflows/api diff --git a/integration-tests/modules/__tests__/link-modules/region-payment-provider.spec.ts b/integration-tests/modules/__tests__/link-modules/region-payment-provider.spec.ts index 0b5be981f8..03b7940d20 100644 --- a/integration-tests/modules/__tests__/link-modules/region-payment-provider.spec.ts +++ b/integration-tests/modules/__tests__/link-modules/region-payment-provider.spec.ts @@ -1,6 +1,7 @@ import { ModuleRegistrationName, Modules } from "@medusajs/modules-sdk" import { IPaymentModuleService, IRegionModuleService } from "@medusajs/types" import { medusaIntegrationTestRunner } from "medusa-test-utils" +import {ContainerRegistrationKeys} from "@medusajs/utils"; jest.setTimeout(50000) @@ -20,8 +21,8 @@ medusaIntegrationTestRunner({ appContainer = getContainer() regionModule = appContainer.resolve(ModuleRegistrationName.REGION) paymentModule = appContainer.resolve(ModuleRegistrationName.PAYMENT) - remoteQuery = appContainer.resolve("remoteQuery") - remoteLink = appContainer.resolve("remoteLink") + remoteQuery = appContainer.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + remoteLink = appContainer.resolve(ContainerRegistrationKeys.REMOTE_LINK) }) it("should query region and payment provider link with remote query", async () => { @@ -73,7 +74,7 @@ medusaIntegrationTestRunner({ ]) ) - expect(otherLink).toHaveLength(1) + expect(otherLink).toHaveLength(2) expect(otherLink).toEqual( expect.arrayContaining([ expect.objectContaining({ @@ -84,6 +85,10 @@ medusaIntegrationTestRunner({ }), ]), }), + expect.objectContaining({ + id: "pp_system_default_2", + regions: [] + }), ]) ) }) diff --git a/integration-tests/modules/__tests__/regions/admin/regions.spec.ts b/integration-tests/modules/__tests__/regions/admin/regions.spec.ts index db46dad999..48efb58bb5 100644 --- a/integration-tests/modules/__tests__/regions/admin/regions.spec.ts +++ b/integration-tests/modules/__tests__/regions/admin/regions.spec.ts @@ -47,10 +47,9 @@ medusaIntegrationTestRunner({ metadata: { foo: "bar" }, }) ) - expect(created.data.region.countries.map((c) => c.iso_2)).toEqual([ - "us", - "ca", - ]) + expect( + created.data.region.countries.map((c) => c.iso_2).sort() + ).toEqual(["ca", "us"]) const updated = await api.post( `/admin/regions/${created.data.region.id}`, @@ -96,6 +95,174 @@ medusaIntegrationTestRunner({ expect(deletedRegion.deleted_at).toBeTruthy() }) + it("should create the region with the available payment providers if the providers exists", async () => { + const paymentProviderId = "pp_system_default" + + const created = await api.post( + `/admin/regions?fields=*payment_providers`, + { + name: "Test Region", + currency_code: "usd", + countries: ["us", "ca"], + metadata: { foo: "bar" }, + payment_providers: [paymentProviderId], + }, + adminHeaders + ) + + expect(created.status).toEqual(200) + expect(created.data.region).toEqual( + expect.objectContaining({ + id: created.data.region.id, + name: "Test Region", + currency_code: "usd", + metadata: { foo: "bar" }, + payment_providers: [ + expect.objectContaining({ + id: paymentProviderId, + }), + ], + }) + ) + }) + + it("should update the region available payment providers", async () => { + const paymentProviderId = "pp_system_default" + const paymentProvider2Id = "pp_system_default_2" + + const created = await api.post( + `/admin/regions`, + { + name: "Test Region", + currency_code: "usd", + countries: ["us", "ca"], + metadata: { foo: "bar" }, + }, + adminHeaders + ) + + /** + * Assign a new payment provider + */ + + await api.post( + `/admin/regions/${created.data.region.id}`, + { + payment_providers: [paymentProviderId], + }, + adminHeaders + ) + + let regionResponse = await api.get( + `/admin/regions/${created.data.region.id}?fields=*payment_providers`, + adminHeaders + ) + + expect(regionResponse.status).toEqual(200) + expect(regionResponse.data.region.payment_providers).toHaveLength(1) + expect(regionResponse.data.region).toEqual( + expect.objectContaining({ + id: regionResponse.data.region.id, + payment_providers: [ + expect.objectContaining({ + id: paymentProviderId, + }), + ], + }) + ) + + /** + * Replace the region payment providers by a new one set of providers + */ + + await api.post( + `/admin/regions/${created.data.region.id}`, + { + payment_providers: [paymentProvider2Id], + }, + adminHeaders + ) + + regionResponse = await api.get( + `/admin/regions/${created.data.region.id}?fields=*payment_providers`, + adminHeaders + ) + + expect(regionResponse.status).toEqual(200) + expect(regionResponse.data.region.payment_providers).toHaveLength(1) + expect(regionResponse.data.region).toEqual( + expect.objectContaining({ + id: regionResponse.data.region.id, + payment_providers: [ + expect.objectContaining({ + id: paymentProvider2Id, + }), + ], + }) + ) + + /** + * Replace the region payment providers with both providers + */ + + await api.post( + `/admin/regions/${created.data.region.id}`, + { + payment_providers: [paymentProviderId, paymentProvider2Id], + }, + adminHeaders + ) + + regionResponse = await api.get( + `/admin/regions/${created.data.region.id}?fields=*payment_providers`, + adminHeaders + ) + + expect(regionResponse.status).toEqual(200) + expect(regionResponse.data.region.payment_providers).toHaveLength(2) + expect(regionResponse.data.region).toEqual( + expect.objectContaining({ + id: regionResponse.data.region.id, + payment_providers: [ + expect.objectContaining({ + id: paymentProvider2Id, + }), + expect.objectContaining({ + id: paymentProviderId, + }), + ], + }) + ) + }) + + it("should throw on update if the given payment providers does not exists", async () => { + const created = await api.post( + `/admin/regions`, + { + name: "Test Region", + currency_code: "usd", + countries: ["us", "ca"], + metadata: { foo: "bar" }, + }, + adminHeaders + ) + + const updateErr = await api + .post( + `/admin/regions/${created.data.region.id}`, + { + payment_providers: ["test"], + }, + adminHeaders + ) + .catch((e) => e) + + expect(updateErr.response.status).toEqual(404) + expect(updateErr.response.data.message).toEqual( + "Payment providers with ids test not found or not enabled" + ) + }) + it("should throw on missing required properties in create", async () => { const err = await api .post(`/admin/regions`, {}, adminHeaders) diff --git a/integration-tests/modules/__tests__/regions/workflows/create-region.spec.ts b/integration-tests/modules/__tests__/regions/workflows/create-region.spec.ts new file mode 100644 index 0000000000..28b104e2c6 --- /dev/null +++ b/integration-tests/modules/__tests__/regions/workflows/create-region.spec.ts @@ -0,0 +1,148 @@ +import { medusaIntegrationTestRunner } from "medusa-test-utils" +import { createRegionsWorkflow } from "@medusajs/core-flows" +import { MedusaContainer, RegionDTO } from "@medusajs/types" +import { createAdminUser } from "../../../../helpers/create-admin-user" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" + +jest.setTimeout(200000) + +const env = { MEDUSA_FF_MEDUSA_V2: true } +const adminHeaders = { + headers: { "x-medusa-access-token": "test_token" }, +} + +medusaIntegrationTestRunner({ + env, + testSuite: ({ dbConnection, getContainer, api }) => { + let container: MedusaContainer + let region: RegionDTO + + beforeAll(() => { + container = getContainer() + }) + + beforeEach(async () => { + await createAdminUser(dbConnection, adminHeaders, container) + }) + + describe("create region workflow", () => { + it("should create a region", async () => { + const paymentProviderId = "pp_system_default" + + const data = { + name: "Test Region", + currency_code: "usd", + countries: ["us", "ca"], + metadata: { foo: "bar" }, + payment_providers: [paymentProviderId], + } + + let { + result: [createRegion], + } = await createRegionsWorkflow(container).run({ + input: { + regions: [data], + }, + }) + + const remoteQuery = container.resolve( + ContainerRegistrationKeys.REMOTE_QUERY + ) + + ;[createRegion] = await remoteQuery( + remoteQueryObjectFromString({ + entryPoint: "region", + variables: { + filters: { + id: createRegion.id, + }, + }, + fields: [ + "id", + "name", + "currency_code", + "metadata", + "countries.*", + "payment_providers.*", + ], + }) + ) + + expect(createRegion).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: data.name, + currency_code: data.currency_code, + countries: expect.arrayContaining( + data.countries.map((iso_2) => expect.objectContaining({ iso_2 })) + ), + metadata: data.metadata, + payment_providers: [ + expect.objectContaining({ + id: paymentProviderId, + }), + ], + }) + ) + }) + + it("should revert the created region and payment providers", async () => { + const paymentProviderId = "pp_system_default" + + const data = { + name: "Test Region", + currency_code: "usd", + countries: ["us", "ca"], + metadata: { foo: "bar" }, + payment_providers: [paymentProviderId], + } + + const workflow = createRegionsWorkflow(container) + workflow.addAction( + "throw", + { + invoke: async function failStep() { + throw new Error(`Failed to create region`) + }, + }, + { + noCompensation: true, + } + ) + + const { errors } = await workflow.run({ + input: { + regions: [data], + }, + throwOnError: false, + }) + + expect(errors).toHaveLength(1) + expect(errors[0].error.message).toEqual(`Failed to create region`) + + const remoteQuery = container.resolve( + ContainerRegistrationKeys.REMOTE_QUERY + ) + + const createRegions = await remoteQuery( + remoteQueryObjectFromString({ + entryPoint: "region", + fields: [ + "id", + "name", + "currency_code", + "metadata", + "countries.*", + "payment_providers.*", + ], + }) + ) + + expect(createRegions).toHaveLength(0) + }) + }) + }, +}) diff --git a/integration-tests/modules/__tests__/regions/workflows/update-region.spec.ts b/integration-tests/modules/__tests__/regions/workflows/update-region.spec.ts new file mode 100644 index 0000000000..4b5063ee91 --- /dev/null +++ b/integration-tests/modules/__tests__/regions/workflows/update-region.spec.ts @@ -0,0 +1,112 @@ +import { medusaIntegrationTestRunner } from "medusa-test-utils" +import { updateRegionsWorkflow } from "@medusajs/core-flows" +import {ContainerLike, MedusaContainer, RegionDTO} from "@medusajs/types" +import { createAdminUser } from "../../../../helpers/create-admin-user" + +jest.setTimeout(200000) + +const env = { MEDUSA_FF_MEDUSA_V2: true } +const adminHeaders = { + headers: { "x-medusa-access-token": "test_token" }, +} + +medusaIntegrationTestRunner({ + env, + testSuite: ({ dbConnection, getContainer, api }) => { + let container: MedusaContainer + let region: RegionDTO + + beforeAll(() => { + container = getContainer() + }) + + beforeEach(async () => { + await createAdminUser(dbConnection, adminHeaders, container) + + region = ( + await api.post( + `/admin/regions`, + { + name: "Test Region", + currency_code: "usd", + countries: ["us", "ca"], + metadata: { foo: "bar" }, + }, + adminHeaders + ) + ).data.region + }) + + describe("update region workflow", () => { + it("should update a region", async () => { + const updateData = { + name: "United States update", + } + + const { + result: [updatedRegion], + } = await updateRegionsWorkflow(container).run({ + input: { + selector: { id: region.id }, + update: updateData, + }, + }) + + expect(updatedRegion).toEqual( + expect.objectContaining({ + id: region.id, + name: updateData.name, + }) + ) + }) + + it("should revert region update and payment providers update when it fails", async () => { + const paymentProviderId = "pp_system_default" + const paymentProvider2Id = "pp_system_default_2" + const updateData = { + name: "United States update", + payment_providers: [paymentProviderId, paymentProvider2Id], + } + + const workflow = updateRegionsWorkflow(container) + workflow.addAction( + "throw", + { + invoke: async function failStep() { + throw new Error(`Failed to update region`) + }, + }, + { + noCompensation: true, + } + ) + + const { errors } = await workflow.run({ + input: { + selector: { id: region.id }, + update: updateData, + }, + throwOnError: false, + }) + + expect(errors).toHaveLength(1) + expect(errors[0].error.message).toEqual(`Failed to update region`) + + const updatedRegion = ( + await api.get( + `/admin/regions/${region.id}?fields=*payment_providers`, + adminHeaders + ) + ).data.region + + expect(updatedRegion).toEqual( + expect.objectContaining({ + id: region.id, + name: region.name, + payment_providers: [], + }) + ) + }) + }) + }, +}) diff --git a/integration-tests/modules/medusa-config.js b/integration-tests/modules/medusa-config.js index 96060a12a9..21391f9801 100644 --- a/integration-tests/modules/medusa-config.js +++ b/integration-tests/modules/medusa-config.js @@ -10,6 +10,17 @@ process.env.LOG_LEVEL = "error" const enableMedusaV2 = process.env.MEDUSA_FF_MEDUSA_V2 == "true" +const customPaymentProvider = { + resolve: { + services: [require("@medusajs/payment/dist/providers/system").default], + }, + options: { + config: { + default_2: {}, + }, + }, +} + module.exports = { plugins: [], projectConfig: { @@ -70,7 +81,13 @@ module.exports = { [Modules.STORE]: true, [Modules.TAX]: true, [Modules.CURRENCY]: true, - [Modules.PAYMENT]: true, + [Modules.PAYMENT]: { + resolve: "@medusajs/payment", + /** @type {import('@medusajs/payment').PaymentModuleOptions}*/ + options: { + providers: [customPaymentProvider], + }, + }, [Modules.FULFILLMENT]: { /** @type {import('@medusajs/fulfillment').FulfillmentModuleOptions} */ options: { diff --git a/packages/core-flows/src/region/steps/set-regions-payment-providers.ts b/packages/core-flows/src/region/steps/set-regions-payment-providers.ts new file mode 100644 index 0000000000..ff28df7505 --- /dev/null +++ b/packages/core-flows/src/region/steps/set-regions-payment-providers.ts @@ -0,0 +1,216 @@ +import { ModuleRegistrationName, RemoteLink } from "@medusajs/modules-sdk" +import { IPaymentModuleService, RemoteQueryFunction } from "@medusajs/types" +import { createStep, StepResponse } from "@medusajs/workflows-sdk" +import { + arrayDifference, + ContainerRegistrationKeys, + LINKS, + MedusaError, + Modules, + promiseAll, + remoteQueryObjectFromString, +} from "@medusajs/utils" + +export interface SetRegionsPaymentProvidersStepInput { + input: { + id: string + payment_providers?: string[] + }[] +} + +interface FilteredSetRegionsPaymentProvidersStepInput { + id: string + payment_providers: string[] +} + +type LinkItems = { + [Modules.REGION]: { region_id: string } + [Modules.PAYMENT]: { payment_provider_id: string } +}[] + +async function validatePaymentProvidersExists( + paymentService: IPaymentModuleService, + paymentProviderIds: string[] +) { + const paymentProviders = await paymentService.listPaymentProviders({ + id: { $in: paymentProviderIds }, + is_enabled: true, + }) + + const retrievedPaymentProviderIds = paymentProviders.map((p) => p.id) + + const missingProviders = arrayDifference( + paymentProviderIds, + retrievedPaymentProviderIds + ) + + if (missingProviders.length) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `Payment providers with ids ${missingProviders.join( + ", " + )} not found or not enabled` + ) + } +} + +async function getCurrentRegionPaymentProvidersLinks( + regionIds: string[], + { remoteQuery }: { remoteQuery: RemoteQueryFunction } +): Promise< + { + [Modules.REGION]: { region_id: string } + [Modules.PAYMENT]: { payment_provider_id: string } + }[] +> { + const query = remoteQueryObjectFromString({ + service: LINKS.RegionPaymentProvider, + variables: { + filters: { region_id: regionIds }, + take: null, + }, + fields: ["region_id", "payment_provider_id"], + }) + + const regionProviderLinks = (await remoteQuery(query)) as { + region_id: string + payment_provider_id: string + }[] + + return regionProviderLinks.map((region) => { + return { + [Modules.REGION]: { + region_id: region.region_id, + }, + [Modules.PAYMENT]: { + payment_provider_id: region.payment_provider_id, + }, + } + }) +} + +export const setRegionsPaymentProvidersStepId = + "add-region-payment-providers-step" +export const setRegionsPaymentProvidersStep = createStep( + setRegionsPaymentProvidersStepId, + async (data: SetRegionsPaymentProvidersStepInput, { container }) => { + const dataInputToProcess = data.input.filter((inputData) => { + return inputData.payment_providers?.length + }) as FilteredSetRegionsPaymentProvidersStepInput[] + + if (!dataInputToProcess.length) { + return new StepResponse(void 0) + } + + const paymentService = container.resolve( + ModuleRegistrationName.PAYMENT + ) + const remoteLink = container.resolve( + ContainerRegistrationKeys.REMOTE_LINK + ) + const remoteQuery = container.resolve( + ContainerRegistrationKeys.REMOTE_QUERY + ) + + const allPaymentProviderIds = dataInputToProcess + .map((inputData) => { + return inputData.payment_providers! + }) + .flat() + const uniquePaymentProviderIds = Array.from( + new Set(allPaymentProviderIds) + ) + + await validatePaymentProvidersExists( + paymentService, + uniquePaymentProviderIds + ) + + const regionIds = dataInputToProcess.map((inputData) => inputData.id) + const currentExistingLinks = await getCurrentRegionPaymentProvidersLinks( + regionIds, + { remoteQuery } + ) + + const linksToRemove: LinkItems = currentExistingLinks + .filter((existingLink) => { + return !dataInputToProcess.some((input) => { + return ( + input.id === existingLink[Modules.REGION].region_id && + input.payment_providers.includes( + existingLink[Modules.PAYMENT].payment_provider_id + ) + ) + }) + }) + .map((link) => { + return { + [Modules.REGION]: { region_id: link[Modules.REGION].region_id }, + [Modules.PAYMENT]: { + payment_provider_id: link[Modules.PAYMENT].payment_provider_id, + }, + } + }) + + const linksToCreate = dataInputToProcess + .map((inputData) => { + return inputData.payment_providers.map((provider) => { + const alreadyExists = currentExistingLinks.some((link) => { + return ( + link[Modules.REGION].region_id === inputData.id && + link[Modules.PAYMENT].payment_provider_id === provider + ) + }) + + if (alreadyExists) { + return + } + + return { + [Modules.REGION]: { region_id: inputData.id }, + [Modules.PAYMENT]: { payment_provider_id: provider }, + } + }) + }) + .flat() + .filter((d): d is LinkItems[0] => !!d) + + const promises: Promise[] = [] + + if (linksToRemove.length) { + promises.push(remoteLink.dismiss(linksToRemove)) + } + + if (linksToCreate.length) { + promises.push(remoteLink.create(linksToCreate)) + } + + await promiseAll(promises) + + return new StepResponse(void 0, { + linksToCreate: linksToRemove, + linksToRemove: linksToCreate, + }) + }, + async (rollbackData, { container }) => { + if (!rollbackData) { + return + } + + const remoteLink = container.resolve( + ContainerRegistrationKeys.REMOTE_LINK + ) + + const promises: Promise[] = [] + + if (rollbackData.linksToRemove.length) { + promises.push(remoteLink.dismiss(rollbackData.linksToRemove)) + } + + if (rollbackData.linksToCreate.length) { + promises.push(remoteLink.create(rollbackData.linksToCreate)) + } + + await promiseAll(promises) + } +) diff --git a/packages/core-flows/src/region/steps/update-regions.ts b/packages/core-flows/src/region/steps/update-regions.ts index b46bab0f5e..759aa0210b 100644 --- a/packages/core-flows/src/region/steps/update-regions.ts +++ b/packages/core-flows/src/region/steps/update-regions.ts @@ -29,6 +29,10 @@ export const updateRegionsStep = createStep( relations, }) + if (Object.keys(data.update).length === 0) { + return new StepResponse(prevData, []) + } + const regions = await service.update(data.selector, data.update) return new StepResponse(regions, prevData) @@ -48,7 +52,7 @@ export const updateRegionsStep = createStep( name: r.name, currency_code: r.currency_code, metadata: r.metadata, - countries: r.countries.map((c) => c.iso_2), + countries: r.countries?.map((c) => c.iso_2), })) ) } diff --git a/packages/core-flows/src/region/workflows/create-regions.ts b/packages/core-flows/src/region/workflows/create-regions.ts index 3be5b31882..03d25b8781 100644 --- a/packages/core-flows/src/region/workflows/create-regions.ts +++ b/packages/core-flows/src/region/workflows/create-regions.ts @@ -1,13 +1,57 @@ -import { CreateRegionDTO, RegionDTO } from "@medusajs/types" -import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" +import { WorkflowTypes } from "@medusajs/types" +import { + createWorkflow, + transform, + WorkflowData, +} from "@medusajs/workflows-sdk" import { createRegionsStep } from "../steps" - -type WorkflowInput = { regionsData: CreateRegionDTO[] } +import { setRegionsPaymentProvidersStep } from "../steps/set-regions-payment-providers" export const createRegionsWorkflowId = "create-regions" export const createRegionsWorkflow = createWorkflow( createRegionsWorkflowId, - (input: WorkflowData): WorkflowData => { - return createRegionsStep(input.regionsData) + ( + input: WorkflowData + ): WorkflowData => { + const data = transform(input, (data) => { + const regionIndexToPaymentProviders = data.regions.map( + (region, index) => { + return { + region_index: index, + payment_providers: region.payment_providers, + } + } + ) + + return { + regions: data.regions, + regionIndexToPaymentProviders, + } + }) + + const regions = createRegionsStep(data.regions) + + const normalizedRegionProviderData = transform( + { + regionIndexToPaymentProviders: data.regionIndexToPaymentProviders, + regions, + }, + (data) => { + return data.regionIndexToPaymentProviders.map( + ({ region_index, payment_providers }) => { + return { + id: data.regions[region_index].id, + payment_providers, + } + } + ) + } + ) + + setRegionsPaymentProvidersStep({ + input: normalizedRegionProviderData, + }) + + return regions } ) diff --git a/packages/core-flows/src/region/workflows/update-regions.ts b/packages/core-flows/src/region/workflows/update-regions.ts index 50855dc3a7..d5be031094 100644 --- a/packages/core-flows/src/region/workflows/update-regions.ts +++ b/packages/core-flows/src/region/workflows/update-regions.ts @@ -1,22 +1,46 @@ +import { WorkflowTypes } from "@medusajs/types" import { - FilterableRegionProps, - RegionDTO, - UpdateRegionDTO, -} from "@medusajs/types" -import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" + createWorkflow, + transform, + WorkflowData, +} from "@medusajs/workflows-sdk" import { updateRegionsStep } from "../steps" - -type UpdateRegionsStepInput = { - selector: FilterableRegionProps - update: UpdateRegionDTO -} - -type WorkflowInput = UpdateRegionsStepInput +import { setRegionsPaymentProvidersStep } from "../steps/set-regions-payment-providers" export const updateRegionsWorkflowId = "update-regions" export const updateRegionsWorkflow = createWorkflow( updateRegionsWorkflowId, - (input: WorkflowData): WorkflowData => { - return updateRegionsStep(input) + ( + input: WorkflowData + ): WorkflowData => { + const data = transform(input, (data) => { + const { selector, update } = data + const { payment_providers = [], ...rest } = update + return { + selector, + update: rest, + payment_providers, + } + }) + + const regions = updateRegionsStep(data) + + const upsertProvidersNormalizedInput = transform( + { data, regions }, + (data) => { + return data.regions.map((region) => { + return { + id: region.id, + payment_providers: data.data.payment_providers, + } + }) + } + ) + + setRegionsPaymentProvidersStep({ + input: upsertProvidersNormalizedInput, + }) + + return regions } ) diff --git a/packages/link-modules/src/definitions/cart-payment-collection.ts b/packages/link-modules/src/definitions/cart-payment-collection.ts index f07e6da6b4..dd35089522 100644 --- a/packages/link-modules/src/definitions/cart-payment-collection.ts +++ b/packages/link-modules/src/definitions/cart-payment-collection.ts @@ -1,6 +1,6 @@ import { Modules } from "@medusajs/modules-sdk" import { ModuleJoinerConfig } from "@medusajs/types" -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const CartPaymentCollection: ModuleJoinerConfig = { serviceName: LINKS.CartPaymentCollection, diff --git a/packages/link-modules/src/definitions/cart-promotion.ts b/packages/link-modules/src/definitions/cart-promotion.ts index c14221cda0..a2f1b160ef 100644 --- a/packages/link-modules/src/definitions/cart-promotion.ts +++ b/packages/link-modules/src/definitions/cart-promotion.ts @@ -1,6 +1,6 @@ import { Modules } from "@medusajs/modules-sdk" import { ModuleJoinerConfig } from "@medusajs/types" -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const CartPromotion: ModuleJoinerConfig = { serviceName: LINKS.CartPromotion, diff --git a/packages/link-modules/src/definitions/fulfillment-set-location.ts b/packages/link-modules/src/definitions/fulfillment-set-location.ts index d09a15b14e..d4703d5334 100644 --- a/packages/link-modules/src/definitions/fulfillment-set-location.ts +++ b/packages/link-modules/src/definitions/fulfillment-set-location.ts @@ -1,6 +1,6 @@ import { Modules } from "@medusajs/modules-sdk" import { ModuleJoinerConfig } from "@medusajs/types" -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const FulfillmentSetLocation: ModuleJoinerConfig = { serviceName: LINKS.FulfillmentSetLocation, diff --git a/packages/link-modules/src/definitions/order-sales-channel.ts b/packages/link-modules/src/definitions/order-sales-channel.ts index 5ddc4678b1..c771fb7857 100644 --- a/packages/link-modules/src/definitions/order-sales-channel.ts +++ b/packages/link-modules/src/definitions/order-sales-channel.ts @@ -1,6 +1,5 @@ import { ModuleJoinerConfig } from "@medusajs/types" - -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const OrderSalesChannel: ModuleJoinerConfig = { serviceName: LINKS.OrderSalesChannel, diff --git a/packages/link-modules/src/definitions/product-sales-channel.ts b/packages/link-modules/src/definitions/product-sales-channel.ts index a7cc47688c..dde30c4bd3 100644 --- a/packages/link-modules/src/definitions/product-sales-channel.ts +++ b/packages/link-modules/src/definitions/product-sales-channel.ts @@ -1,6 +1,6 @@ import { Modules } from "@medusajs/modules-sdk" import { ModuleJoinerConfig } from "@medusajs/types" -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const ProductSalesChannel: ModuleJoinerConfig = { serviceName: LINKS.ProductSalesChannel, diff --git a/packages/link-modules/src/definitions/product-shipping-profile.ts b/packages/link-modules/src/definitions/product-shipping-profile.ts index 7805390d53..62e5a3d84b 100644 --- a/packages/link-modules/src/definitions/product-shipping-profile.ts +++ b/packages/link-modules/src/definitions/product-shipping-profile.ts @@ -1,6 +1,6 @@ import { Modules } from "@medusajs/modules-sdk" import { ModuleJoinerConfig } from "@medusajs/types" -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const ProductShippingProfile: ModuleJoinerConfig = { serviceName: LINKS.ProductShippingProfile, diff --git a/packages/link-modules/src/definitions/product-variant-inventory-item.ts b/packages/link-modules/src/definitions/product-variant-inventory-item.ts index f5911a0e15..e17273fe4a 100644 --- a/packages/link-modules/src/definitions/product-variant-inventory-item.ts +++ b/packages/link-modules/src/definitions/product-variant-inventory-item.ts @@ -1,6 +1,6 @@ import { Modules } from "@medusajs/modules-sdk" import { ModuleJoinerConfig } from "@medusajs/types" -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const ProductVariantInventoryItem: ModuleJoinerConfig = { serviceName: LINKS.ProductVariantInventoryItem, diff --git a/packages/link-modules/src/definitions/product-variant-price-set.ts b/packages/link-modules/src/definitions/product-variant-price-set.ts index 26b771bec3..2daf117205 100644 --- a/packages/link-modules/src/definitions/product-variant-price-set.ts +++ b/packages/link-modules/src/definitions/product-variant-price-set.ts @@ -1,6 +1,6 @@ import { Modules } from "@medusajs/modules-sdk" import { ModuleJoinerConfig } from "@medusajs/types" -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const ProductVariantPriceSet: ModuleJoinerConfig = { serviceName: LINKS.ProductVariantPriceSet, diff --git a/packages/link-modules/src/definitions/publishable-api-key-sales-channel.ts b/packages/link-modules/src/definitions/publishable-api-key-sales-channel.ts index 132bfcba3a..0d4bb07780 100644 --- a/packages/link-modules/src/definitions/publishable-api-key-sales-channel.ts +++ b/packages/link-modules/src/definitions/publishable-api-key-sales-channel.ts @@ -1,6 +1,6 @@ import { Modules } from "@medusajs/modules-sdk" import { ModuleJoinerConfig } from "@medusajs/types" -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const PublishableApiKeySalesChannel: ModuleJoinerConfig = { serviceName: LINKS.PublishableApiKeySalesChannel, diff --git a/packages/link-modules/src/definitions/region-payment-provider.ts b/packages/link-modules/src/definitions/region-payment-provider.ts index 0366ed26c6..3b98256bc1 100644 --- a/packages/link-modules/src/definitions/region-payment-provider.ts +++ b/packages/link-modules/src/definitions/region-payment-provider.ts @@ -1,6 +1,6 @@ import { Modules } from "@medusajs/modules-sdk" import { ModuleJoinerConfig } from "@medusajs/types" -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const RegionPaymentProvider: ModuleJoinerConfig = { serviceName: LINKS.RegionPaymentProvider, diff --git a/packages/link-modules/src/definitions/sales-channel-location.ts b/packages/link-modules/src/definitions/sales-channel-location.ts index 33bf20f03c..fd79ef239e 100644 --- a/packages/link-modules/src/definitions/sales-channel-location.ts +++ b/packages/link-modules/src/definitions/sales-channel-location.ts @@ -1,6 +1,6 @@ import { Modules } from "@medusajs/modules-sdk" import { ModuleJoinerConfig } from "@medusajs/types" -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const SalesChannelLocation: ModuleJoinerConfig = { serviceName: LINKS.SalesChannelLocation, diff --git a/packages/link-modules/src/definitions/shipping-option-price-set.ts b/packages/link-modules/src/definitions/shipping-option-price-set.ts index 2e8337be16..90d3d56193 100644 --- a/packages/link-modules/src/definitions/shipping-option-price-set.ts +++ b/packages/link-modules/src/definitions/shipping-option-price-set.ts @@ -1,6 +1,6 @@ import { Modules } from "@medusajs/modules-sdk" import { ModuleJoinerConfig } from "@medusajs/types" -import { LINKS } from "../links" +import { LINKS } from "@medusajs/utils" export const ShippingOptionPriceSet: ModuleJoinerConfig = { serviceName: LINKS.ShippingOptionPriceSet, diff --git a/packages/medusa-test-utils/src/medusa-test-runner.ts b/packages/medusa-test-utils/src/medusa-test-runner.ts index 6f4b873afa..0d4aa3223b 100644 --- a/packages/medusa-test-utils/src/medusa-test-runner.ts +++ b/packages/medusa-test-utils/src/medusa-test-runner.ts @@ -2,7 +2,7 @@ import { getDatabaseURL } from "./database" import { initDb } from "./medusa-test-runner-utils/use-db" import { startBootstrapApp } from "./medusa-test-runner-utils/bootstrap-app" import { createDatabase, dropDatabase } from "pg-god" -import { ContainerLike } from "@medusajs/types" +import {ContainerLike, MedusaContainer} from "@medusajs/types" import { createMedusaContainer } from "@medusajs/utils" const axios = require("axios").default @@ -70,7 +70,7 @@ const dbTestUtilFactory = (): any => ({ export interface MedusaSuiteOptions { dbUtils: any dbConnection: any // Legacy typeorm connection - getContainer: () => ContainerLike + getContainer: () => MedusaContainer api: any dbConfig: { dbName: string @@ -89,7 +89,7 @@ export function medusaIntegrationTestRunner({ testSuite, }: { moduleName?: string - env?: Record + env?: Record dbName?: string schema?: string debug?: boolean diff --git a/packages/medusa-test-utils/src/module-test-runner.ts b/packages/medusa-test-utils/src/module-test-runner.ts index 1c5ca7bfca..27acd6273f 100644 --- a/packages/medusa-test-utils/src/module-test-runner.ts +++ b/packages/medusa-test-utils/src/module-test-runner.ts @@ -34,7 +34,7 @@ export function moduleIntegrationTestRunner({ injectedDependencies?: Record resolve?: string debug?: boolean - testSuite: (options: SuiteOptions) => () => void + testSuite: (options: SuiteOptions) => void }) { const moduleSdkImports = require("@medusajs/modules-sdk") diff --git a/packages/medusa/src/api-v2/admin/regions/[id]/route.ts b/packages/medusa/src/api-v2/admin/regions/[id]/route.ts index c6c3d17a9d..720e05f401 100644 --- a/packages/medusa/src/api-v2/admin/regions/[id]/route.ts +++ b/packages/medusa/src/api-v2/admin/regions/[id]/route.ts @@ -8,8 +8,10 @@ import { } from "@medusajs/core-flows" import { UpdateRegionDTO } from "@medusajs/types" -import { defaultAdminRegionFields } from "../query-config" -import { remoteQueryObjectFromString } from "@medusajs/utils" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString +} from "@medusajs/utils" export const GET = async ( req: AuthenticatedMedusaRequest, @@ -22,7 +24,7 @@ export const GET = async ( const queryObject = remoteQueryObjectFromString({ entryPoint: "region", variables, - fields: defaultAdminRegionFields, + fields: req.remoteQueryConfig.fields, }) const [region] = await remoteQuery(queryObject) @@ -46,7 +48,19 @@ export const POST = async ( throw errors[0].error } - res.status(200).json({ region: result[0] }) + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + + const queryObject = remoteQueryObjectFromString({ + entryPoint: "region", + variables: { + filters: { id: req.params.id }, + }, + fields: req.remoteQueryConfig.fields, + }) + + const regions = await remoteQuery(queryObject) + + res.status(200).json({ region: regions[0] }) } export const DELETE = async ( diff --git a/packages/medusa/src/api-v2/admin/regions/middlewares.ts b/packages/medusa/src/api-v2/admin/regions/middlewares.ts index dbd08bcf68..220ac69264 100644 --- a/packages/medusa/src/api-v2/admin/regions/middlewares.ts +++ b/packages/medusa/src/api-v2/admin/regions/middlewares.ts @@ -40,11 +40,23 @@ export const adminRegionRoutesMiddlewares: MiddlewareRoute[] = [ { method: ["POST"], matcher: "/admin/regions", - middlewares: [transformBody(AdminPostRegionsReq)], + middlewares: [ + transformQuery( + AdminGetRegionsRegionParams, + QueryConfig.retrieveTransformQueryConfig + ), + transformBody(AdminPostRegionsReq), + ], }, { method: ["POST"], matcher: "/admin/regions/:id", - middlewares: [transformBody(AdminPostRegionsRegionReq)], + middlewares: [ + transformQuery( + AdminGetRegionsRegionParams, + QueryConfig.retrieveTransformQueryConfig + ), + transformBody(AdminPostRegionsRegionReq), + ], }, ] diff --git a/packages/medusa/src/api-v2/admin/regions/query-config.ts b/packages/medusa/src/api-v2/admin/regions/query-config.ts index a10e71b995..d3d80646ad 100644 --- a/packages/medusa/src/api-v2/admin/regions/query-config.ts +++ b/packages/medusa/src/api-v2/admin/regions/query-config.ts @@ -1,5 +1,3 @@ -export const defaultAdminRegionRelations = ["countries"] -export const allowedAdminRegionRelations = ["countries"] export const defaultAdminRegionFields = [ "id", "name", @@ -16,13 +14,12 @@ export const defaultAdminRegionFields = [ ] export const retrieveTransformQueryConfig = { - defaultFields: defaultAdminRegionFields, - defaultRelations: defaultAdminRegionRelations, - allowedRelations: allowedAdminRegionRelations, + defaults: defaultAdminRegionFields, isList: false, } export const listTransformQueryConfig = { + defaults: defaultAdminRegionFields, defaultLimit: 20, isList: true, } diff --git a/packages/medusa/src/api-v2/admin/regions/route.ts b/packages/medusa/src/api-v2/admin/regions/route.ts index 0a250b0b5b..4621a092c5 100644 --- a/packages/medusa/src/api-v2/admin/regions/route.ts +++ b/packages/medusa/src/api-v2/admin/regions/route.ts @@ -5,24 +5,24 @@ import { import { CreateRegionDTO } from "@medusajs/types" import { createRegionsWorkflow } from "@medusajs/core-flows" -import { defaultAdminRegionFields } from "./query-config" -import { remoteQueryObjectFromString } from "@medusajs/utils" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" export const GET = async ( req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { - const remoteQuery = req.scope.resolve("remoteQuery") + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) const queryObject = remoteQueryObjectFromString({ entryPoint: "region", variables: { filters: req.filterableFields, - order: req.listConfig.order, - skip: req.listConfig.skip, - take: req.listConfig.take, + ...req.remoteQueryConfig.pagination, }, - fields: defaultAdminRegionFields, + fields: req.remoteQueryConfig.fields, }) const { rows: regions, metadata } = await remoteQuery(queryObject) @@ -46,7 +46,7 @@ export const POST = async ( ] const { result, errors } = await createRegionsWorkflow(req.scope).run({ - input: { regionsData: input }, + input: { regions: input }, throwOnError: false, }) @@ -54,5 +54,17 @@ export const POST = async ( throw errors[0].error } - res.status(200).json({ region: result[0] }) + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + + const queryObject = remoteQueryObjectFromString({ + entryPoint: "region", + variables: { + filters: { id: result[0].id }, + }, + fields: req.remoteQueryConfig.fields, + }) + + const regions = await remoteQuery(queryObject) + + res.status(200).json({ region: regions[0] }) } diff --git a/packages/medusa/src/api-v2/admin/regions/validators.ts b/packages/medusa/src/api-v2/admin/regions/validators.ts index 8fd977f5d9..833739030d 100644 --- a/packages/medusa/src/api-v2/admin/regions/validators.ts +++ b/packages/medusa/src/api-v2/admin/regions/validators.ts @@ -7,7 +7,7 @@ import { IsString, ValidateNested, } from "class-validator" -import { FindParams, extendedFindParamsMixin } from "../../../types/common" +import { extendedFindParamsMixin, FindParams } from "../../../types/common" import { OperatorMapValidator } from "../../../types/validators/operator-map" export class AdminGetRegionsRegionParams extends FindParams {} @@ -90,6 +90,11 @@ export class AdminPostRegionsReq { @IsObject() @IsOptional() metadata?: Record + + @IsOptional() + @IsArray() + @IsString({ each: true }) + payment_providers?: string[] } export class AdminPostRegionsRegionReq { @@ -108,4 +113,9 @@ export class AdminPostRegionsRegionReq { @IsObject() @IsOptional() metadata?: Record + + @IsOptional() + @IsArray() + @IsString({ each: true }) + payment_providers?: string[] } diff --git a/packages/modules-sdk/src/definitions.ts b/packages/modules-sdk/src/definitions.ts index 8881451fa1..df52c5d92a 100644 --- a/packages/modules-sdk/src/definitions.ts +++ b/packages/modules-sdk/src/definitions.ts @@ -11,6 +11,7 @@ export enum LinkModuleUtils { REMOTE_LINK = "remoteLink", } +// TODO: Remove this enum and use the one from @medusajs/utils export enum Modules { AUTH = "auth", CACHE = "cacheService", diff --git a/packages/orchestration/src/joiner/helpers.ts b/packages/orchestration/src/joiner/helpers.ts index 32ef4a091a..bc612c0867 100644 --- a/packages/orchestration/src/joiner/helpers.ts +++ b/packages/orchestration/src/joiner/helpers.ts @@ -70,7 +70,11 @@ export function toRemoteJoinerQuery( } if (isEntryPoint) { - remoteJoinerQuery.alias = key + if (value.isServiceAccess) { + remoteJoinerQuery.service = key + } else { + remoteJoinerQuery.alias = key + } } else { remoteJoinerQuery.expands!.push(expandObj) } diff --git a/packages/payment/src/index.ts b/packages/payment/src/index.ts index d449f73544..d6bb9fb737 100644 --- a/packages/payment/src/index.ts +++ b/packages/payment/src/index.ts @@ -8,3 +8,4 @@ export default moduleDefinition export { revertMigration, runMigrations } export * from "./initialize" +export * from "./types" diff --git a/packages/payment/src/types/index.ts b/packages/payment/src/types/index.ts index 0f252977b0..5e299a7aff 100644 --- a/packages/payment/src/types/index.ts +++ b/packages/payment/src/types/index.ts @@ -1,5 +1,27 @@ -import { Logger } from "@medusajs/types" +import { + Logger, + ModuleProviderExports, + ModuleServiceInitializeOptions, +} from "@medusajs/types" export type InitializeModuleInjectableDependencies = { logger?: Logger } + +export type PaymentModuleOptions = Partial & { + /** + * Providers to be registered + */ + providers?: { + /** + * The module provider to be registered + */ + resolve: string | ModuleProviderExports + options: { + /** + * key value pair of the provider name and the configuration to be passed to the provider constructor + */ + config: Record + } + }[] +} diff --git a/packages/types/src/payment/common.ts b/packages/types/src/payment/common.ts index 0b3b8c48a2..342a4cc357 100644 --- a/packages/types/src/payment/common.ts +++ b/packages/types/src/payment/common.ts @@ -465,7 +465,7 @@ export interface FilterablePaymentProviderProps /** * The IDs to filter the payment collection by. */ - id?: string | string[] + id?: string | string[] | OperatorMap /** * Filter by enabled status diff --git a/packages/types/src/region/common.ts b/packages/types/src/region/common.ts index 40669b918d..bc67399101 100644 --- a/packages/types/src/region/common.ts +++ b/packages/types/src/region/common.ts @@ -76,7 +76,7 @@ export interface FilterableRegionProps /** * The IDs to filter the regions by. */ - id?: string[] | string + id?: string[] | string | OperatorMap /** * Filter regions by their name. */ diff --git a/packages/types/src/workflow/index.ts b/packages/types/src/workflow/index.ts index ae6f28603a..a9550b4326 100644 --- a/packages/types/src/workflow/index.ts +++ b/packages/types/src/workflow/index.ts @@ -4,4 +4,5 @@ export * as ProductWorkflow from "./product" export * as InventoryWorkflow from "./inventory" export * as PriceListWorkflow from "./price-list" export * as UserWorkflow from "./user" +export * as RegionWorkflow from "./region" export * as InviteWorkflow from "./invite" diff --git a/packages/types/src/workflow/region/create-regions.ts b/packages/types/src/workflow/region/create-regions.ts new file mode 100644 index 0000000000..779ad4f12e --- /dev/null +++ b/packages/types/src/workflow/region/create-regions.ts @@ -0,0 +1,9 @@ +import { CreateRegionDTO, RegionDTO } from "../../region" + +export interface CreateRegionsWorkflowInput { + regions: (CreateRegionDTO & { + payment_providers?: string[] + })[] +} + +export type CreateRegionsWorkflowOutput = RegionDTO[] diff --git a/packages/types/src/workflow/region/index.ts b/packages/types/src/workflow/region/index.ts new file mode 100644 index 0000000000..6241d60159 --- /dev/null +++ b/packages/types/src/workflow/region/index.ts @@ -0,0 +1,2 @@ +export * from "./update-regions" +export * from "./create-regions" diff --git a/packages/types/src/workflow/region/update-regions.ts b/packages/types/src/workflow/region/update-regions.ts new file mode 100644 index 0000000000..1c417df0d5 --- /dev/null +++ b/packages/types/src/workflow/region/update-regions.ts @@ -0,0 +1,10 @@ +import { FilterableRegionProps, RegionDTO, UpdateRegionDTO } from "../../region" + +export interface UpdateRegionsWorkflowInput { + selector: FilterableRegionProps + update: UpdateRegionDTO & { + payment_providers?: string[] + } +} + +export type UpdateRegionsWorkflowOutput = RegionDTO[] diff --git a/packages/utils/src/bundles.ts b/packages/utils/src/bundles.ts index 582d185d41..1fc5b18f06 100644 --- a/packages/utils/src/bundles.ts +++ b/packages/utils/src/bundles.ts @@ -13,4 +13,5 @@ export * as SearchUtils from "./search" export * as ShippingProfileUtils from "./shipping" export * as UserUtils from "./user" export * as InventoryUtils from "./inventory" +export * as LinkUtils from "./link" export * as ApiKeyUtils from "./api-key" diff --git a/packages/utils/src/common/__tests__/remote-query-object-from-string.spec.ts b/packages/utils/src/common/__tests__/remote-query-object-from-string.spec.ts index 5cbd967574..d39acc4f2b 100644 --- a/packages/utils/src/common/__tests__/remote-query-object-from-string.spec.ts +++ b/packages/utils/src/common/__tests__/remote-query-object-from-string.spec.ts @@ -48,6 +48,57 @@ describe("remoteQueryObjectFromString", function () { "url", "metadata", ], + isServiceAccess: false, + tags: { + fields: ["id", "created_at", "updated_at", "deleted_at", "value"], + }, + + options: { + fields: [ + "id", + "created_at", + "updated_at", + "deleted_at", + "title", + "product_id", + "metadata", + ], + values: { + fields: [ + "id", + "created_at", + "updated_at", + "deleted_at", + "value", + "option_id", + "variant_id", + "metadata", + ], + }, + }, + }, + }) + }) + + it("should return a remote query object using service entry point", function () { + const output = remoteQueryObjectFromString({ + service: "product", + variables: {}, + fields, + }) + + expect(output).toEqual({ + product: { + __args: {}, + fields: [ + "id", + "created_at", + "updated_at", + "deleted_at", + "url", + "metadata", + ], + isServiceAccess: true, tags: { fields: ["id", "created_at", "updated_at", "deleted_at", "value"], }, diff --git a/packages/utils/src/common/remote-query-object-from-string.ts b/packages/utils/src/common/remote-query-object-from-string.ts index 1a880c7344..000848333a 100644 --- a/packages/utils/src/common/remote-query-object-from-string.ts +++ b/packages/utils/src/common/remote-query-object-from-string.ts @@ -1,8 +1,6 @@ /** * Convert a string fields array to a remote query object - * @param entryPoint - * @param variables - * @param fields + * @param config - The configuration object * * @example * const fields = [ @@ -83,28 +81,41 @@ * // }, * // } */ -export function remoteQueryObjectFromString({ - entryPoint, - variables, - fields, -}: { - entryPoint: string - variables?: any - fields: string[] -}): object { +export function remoteQueryObjectFromString( + config: + | { + entryPoint: string + variables?: any + fields: string[] + } + | { + service: string + variables?: any + fields: string[] + } +): object { + const { entryPoint, service, variables, fields } = { + ...config, + entryPoint: "entryPoint" in config ? config.entryPoint : undefined, + service: "service" in config ? config.service : undefined, + } + + const entryKey = (entryPoint ?? service) as string + const remoteJoinerConfig: object = { - [entryPoint]: { + [entryKey]: { fields: [], + isServiceAccess: !!service, // specifies if the entry point is a service }, } if (variables) { - remoteJoinerConfig[entryPoint]["__args"] = variables + remoteJoinerConfig[entryKey]["__args"] = variables } for (const field of fields) { if (!field.includes(".")) { - remoteJoinerConfig[entryPoint]["fields"].push(field) + remoteJoinerConfig[entryKey]["fields"].push(field) continue } @@ -114,7 +125,7 @@ export function remoteQueryObjectFromString({ const deepConfigRef = fieldSegments.reduce((acc, curr) => { acc[curr] ??= {} return acc[curr] - }, remoteJoinerConfig[entryPoint]) + }, remoteJoinerConfig[entryKey]) deepConfigRef["fields"] ??= [] deepConfigRef["fields"].push(fieldProperty) diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 0939438ef8..649d69d601 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -22,5 +22,6 @@ export * from "./totals" export * from "./totals/big-number" export * from "./user" export * from "./api-key" +export * from "./link" export const MedusaModuleType = Symbol.for("MedusaModule") diff --git a/packages/utils/src/link/compose-link-name.ts b/packages/utils/src/link/compose-link-name.ts new file mode 100644 index 0000000000..ce833ccc14 --- /dev/null +++ b/packages/utils/src/link/compose-link-name.ts @@ -0,0 +1,9 @@ +import { lowerCaseFirst, toPascalCase } from "../common" + +export const composeLinkName = (...args) => { + return lowerCaseFirst(toPascalCase(composeTableName(...args.concat("link")))) +} + +export const composeTableName = (...args) => { + return args.map((name) => name.replace(/(_id|Service)$/gi, "")).join("_") +} diff --git a/packages/utils/src/link/index.ts b/packages/utils/src/link/index.ts new file mode 100644 index 0000000000..62e4f2837a --- /dev/null +++ b/packages/utils/src/link/index.ts @@ -0,0 +1,2 @@ +export * from "./links" +export * from "./compose-link-name" diff --git a/packages/link-modules/src/links.ts b/packages/utils/src/link/links.ts similarity index 94% rename from packages/link-modules/src/links.ts rename to packages/utils/src/link/links.ts index d1809532ae..6fcad2867c 100644 --- a/packages/link-modules/src/links.ts +++ b/packages/utils/src/link/links.ts @@ -1,5 +1,5 @@ -import { Modules } from "@medusajs/modules-sdk" -import { composeLinkName } from "./utils" +import { Modules } from "../modules-sdk" +import { composeLinkName } from "./compose-link-name" export const LINKS = { ProductVariantInventoryItem: composeLinkName( diff --git a/packages/utils/src/modules-sdk/definition.ts b/packages/utils/src/modules-sdk/definition.ts new file mode 100644 index 0000000000..9555cbef00 --- /dev/null +++ b/packages/utils/src/modules-sdk/definition.ts @@ -0,0 +1,24 @@ +export enum Modules { + AUTH = "auth", + CACHE = "cacheService", + CART = "cart", + CUSTOMER = "customer", + EVENT_BUS = "eventBus", + INVENTORY = "inventoryService", + LINK = "linkModules", + PAYMENT = "payment", + PRICING = "pricingService", + PRODUCT = "productService", + PROMOTION = "promotion", + SALES_CHANNEL = "salesChannel", + TAX = "tax", + FULFILLMENT = "fulfillment", + STOCK_LOCATION = "stockLocationService", + USER = "user", + WORKFLOW_ENGINE = "workflows", + REGION = "region", + ORDER = "order", + API_KEY = "apiKey", + STORE = "store", + CURRENCY = "currency", +} diff --git a/packages/utils/src/modules-sdk/index.ts b/packages/utils/src/modules-sdk/index.ts index 5e2011276c..ecd006c03f 100644 --- a/packages/utils/src/modules-sdk/index.ts +++ b/packages/utils/src/modules-sdk/index.ts @@ -8,3 +8,4 @@ export * from "./create-pg-connection" export * from "./migration-scripts" export * from "./internal-module-service-factory" export * from "./abstract-module-service-factory" +export * from "./definition"