feat: region payment providers management workflows/api (#6864)
This commit is contained in:
committed by
GitHub
parent
12fcb655cd
commit
e944a627f0
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user