feat: region payment providers management workflows/api (#6864)
This commit is contained in:
committed by
GitHub
parent
12fcb655cd
commit
e944a627f0
13
.changeset/few-plants-float.md
Normal file
13
.changeset/few-plants-float.md
Normal file
@@ -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
|
||||
@@ -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: []
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -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: [],
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -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: {
|
||||
|
||||
@@ -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<IPaymentModuleService>(
|
||||
ModuleRegistrationName.PAYMENT
|
||||
)
|
||||
const remoteLink = container.resolve<RemoteLink>(
|
||||
ContainerRegistrationKeys.REMOTE_LINK
|
||||
)
|
||||
const remoteQuery = container.resolve<RemoteQueryFunction>(
|
||||
ContainerRegistrationKeys.REMOTE_QUERY
|
||||
)
|
||||
|
||||
const allPaymentProviderIds = dataInputToProcess
|
||||
.map((inputData) => {
|
||||
return inputData.payment_providers!
|
||||
})
|
||||
.flat()
|
||||
const uniquePaymentProviderIds = Array.from(
|
||||
new Set<string>(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<unknown[]>[] = []
|
||||
|
||||
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<RemoteLink>(
|
||||
ContainerRegistrationKeys.REMOTE_LINK
|
||||
)
|
||||
|
||||
const promises: Promise<unknown[]>[] = []
|
||||
|
||||
if (rollbackData.linksToRemove.length) {
|
||||
promises.push(remoteLink.dismiss(rollbackData.linksToRemove))
|
||||
}
|
||||
|
||||
if (rollbackData.linksToCreate.length) {
|
||||
promises.push(remoteLink.create(rollbackData.linksToCreate))
|
||||
}
|
||||
|
||||
await promiseAll(promises)
|
||||
}
|
||||
)
|
||||
@@ -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),
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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<WorkflowInput>): WorkflowData<RegionDTO[]> => {
|
||||
return createRegionsStep(input.regionsData)
|
||||
(
|
||||
input: WorkflowData<WorkflowTypes.RegionWorkflow.CreateRegionsWorkflowInput>
|
||||
): WorkflowData<WorkflowTypes.RegionWorkflow.CreateRegionsWorkflowOutput> => {
|
||||
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
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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<WorkflowInput>): WorkflowData<RegionDTO[]> => {
|
||||
return updateRegionsStep(input)
|
||||
(
|
||||
input: WorkflowData<WorkflowTypes.RegionWorkflow.UpdateRegionsWorkflowInput>
|
||||
): WorkflowData<WorkflowTypes.RegionWorkflow.UpdateRegionsWorkflowOutput> => {
|
||||
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
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<TService = unknown> {
|
||||
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<string, string>
|
||||
env?: Record<string, string | any>
|
||||
dbName?: string
|
||||
schema?: string
|
||||
debug?: boolean
|
||||
|
||||
@@ -34,7 +34,7 @@ export function moduleIntegrationTestRunner({
|
||||
injectedDependencies?: Record<string, any>
|
||||
resolve?: string
|
||||
debug?: boolean
|
||||
testSuite: <TService = unknown>(options: SuiteOptions<TService>) => () => void
|
||||
testSuite: <TService = unknown>(options: SuiteOptions<TService>) => void
|
||||
}) {
|
||||
const moduleSdkImports = require("@medusajs/modules-sdk")
|
||||
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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),
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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] })
|
||||
}
|
||||
|
||||
@@ -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<string, unknown>
|
||||
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
payment_providers?: string[]
|
||||
}
|
||||
|
||||
export class AdminPostRegionsRegionReq {
|
||||
@@ -108,4 +113,9 @@ export class AdminPostRegionsRegionReq {
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
metadata?: Record<string, unknown>
|
||||
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
payment_providers?: string[]
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -8,3 +8,4 @@ export default moduleDefinition
|
||||
export { revertMigration, runMigrations }
|
||||
|
||||
export * from "./initialize"
|
||||
export * from "./types"
|
||||
|
||||
@@ -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<ModuleServiceInitializeOptions> & {
|
||||
/**
|
||||
* 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<string, unknown>
|
||||
}
|
||||
}[]
|
||||
}
|
||||
|
||||
@@ -465,7 +465,7 @@ export interface FilterablePaymentProviderProps
|
||||
/**
|
||||
* The IDs to filter the payment collection by.
|
||||
*/
|
||||
id?: string | string[]
|
||||
id?: string | string[] | OperatorMap<string | string[]>
|
||||
|
||||
/**
|
||||
* Filter by enabled status
|
||||
|
||||
@@ -76,7 +76,7 @@ export interface FilterableRegionProps
|
||||
/**
|
||||
* The IDs to filter the regions by.
|
||||
*/
|
||||
id?: string[] | string
|
||||
id?: string[] | string | OperatorMap<string | string[]>
|
||||
/**
|
||||
* Filter regions by their name.
|
||||
*/
|
||||
|
||||
@@ -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"
|
||||
|
||||
9
packages/types/src/workflow/region/create-regions.ts
Normal file
9
packages/types/src/workflow/region/create-regions.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { CreateRegionDTO, RegionDTO } from "../../region"
|
||||
|
||||
export interface CreateRegionsWorkflowInput {
|
||||
regions: (CreateRegionDTO & {
|
||||
payment_providers?: string[]
|
||||
})[]
|
||||
}
|
||||
|
||||
export type CreateRegionsWorkflowOutput = RegionDTO[]
|
||||
2
packages/types/src/workflow/region/index.ts
Normal file
2
packages/types/src/workflow/region/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./update-regions"
|
||||
export * from "./create-regions"
|
||||
10
packages/types/src/workflow/region/update-regions.ts
Normal file
10
packages/types/src/workflow/region/update-regions.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { FilterableRegionProps, RegionDTO, UpdateRegionDTO } from "../../region"
|
||||
|
||||
export interface UpdateRegionsWorkflowInput {
|
||||
selector: FilterableRegionProps
|
||||
update: UpdateRegionDTO & {
|
||||
payment_providers?: string[]
|
||||
}
|
||||
}
|
||||
|
||||
export type UpdateRegionsWorkflowOutput = RegionDTO[]
|
||||
@@ -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"
|
||||
|
||||
@@ -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"],
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
9
packages/utils/src/link/compose-link-name.ts
Normal file
9
packages/utils/src/link/compose-link-name.ts
Normal file
@@ -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("_")
|
||||
}
|
||||
2
packages/utils/src/link/index.ts
Normal file
2
packages/utils/src/link/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./links"
|
||||
export * from "./compose-link-name"
|
||||
@@ -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(
|
||||
24
packages/utils/src/modules-sdk/definition.ts
Normal file
24
packages/utils/src/modules-sdk/definition.ts
Normal file
@@ -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",
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user