feat(medusa,medusa-react): PaymentCollection support (#2659)
* chore: medusa react, order edit complete fix and single payment session
This commit is contained in:
committed by
GitHub
parent
42d9c7222b
commit
15c667fbd3
@@ -27,7 +27,7 @@ describe("[MEDUSA_FF_ORDER_EDITING] /admin/payment-collections", () => {
|
||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||
const [process, connection] = await startServerWithEnvironment({
|
||||
cwd,
|
||||
env: { MEDUSA_FF_ORDER_EDITING: true },
|
||||
env: { MEDUSA_FF_ORDER_EDITING: true }
|
||||
})
|
||||
dbConnection = connection
|
||||
medusaProcess = process
|
||||
|
||||
@@ -66,14 +66,20 @@ describe("[MEDUSA_FF_ORDER_EDITING] /admin/payment", () => {
|
||||
const api = useApi()
|
||||
|
||||
// create payment session
|
||||
await api.post(`/store/payment-collections/${payCol.id}/sessions`, {
|
||||
sessions: {
|
||||
const payColRes = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions`,
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
amount: 10000,
|
||||
},
|
||||
})
|
||||
await api.post(`/store/payment-collections/${payCol.id}/authorize`)
|
||||
}
|
||||
)
|
||||
await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions/batch/authorize`,
|
||||
{
|
||||
session_ids: payColRes.data.payment_collection.payment_sessions.map(
|
||||
({ id }) => id
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
const paymentCollections = await api.get(
|
||||
`/admin/payment-collections/${payCol.id}`,
|
||||
@@ -85,6 +91,7 @@ describe("[MEDUSA_FF_ORDER_EDITING] /admin/payment", () => {
|
||||
)
|
||||
|
||||
const payment = paymentCollections.data.payment_collection.payments[0]
|
||||
|
||||
expect(payment.captured_at).toBe(null)
|
||||
|
||||
const response = await api.post(
|
||||
@@ -107,14 +114,20 @@ describe("[MEDUSA_FF_ORDER_EDITING] /admin/payment", () => {
|
||||
const api = useApi()
|
||||
|
||||
// create payment session
|
||||
await api.post(`/store/payment-collections/${payCol.id}/sessions`, {
|
||||
sessions: {
|
||||
const payColRes = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions`,
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
amount: 10000,
|
||||
},
|
||||
})
|
||||
await api.post(`/store/payment-collections/${payCol.id}/authorize`)
|
||||
}
|
||||
)
|
||||
await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions/batch/authorize`,
|
||||
{
|
||||
session_ids: payColRes.data.payment_collection.payment_sessions.map(
|
||||
({ id }) => id
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
const paymentCollections = await api.get(
|
||||
`/admin/payment-collections/${payCol.id}`,
|
||||
|
||||
@@ -5,6 +5,9 @@ const startServerWithEnvironment =
|
||||
const { useApi } = require("../../../helpers/use-api")
|
||||
const { useDb } = require("../../../helpers/use-db")
|
||||
const adminSeeder = require("../../helpers/admin-seeder")
|
||||
const {
|
||||
getClientAuthenticationCookie,
|
||||
} = require("../../helpers/client-authentication")
|
||||
const {
|
||||
simpleOrderEditFactory,
|
||||
} = require("../../factories/simple-order-edit-factory")
|
||||
@@ -16,6 +19,7 @@ const {
|
||||
simpleLineItemFactory,
|
||||
simpleProductFactory,
|
||||
simpleOrderFactory,
|
||||
simpleCustomerFactory,
|
||||
} = require("../../factories")
|
||||
const { OrderEditItemChangeType } = require("@medusajs/medusa")
|
||||
|
||||
@@ -33,6 +37,11 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/order-edits", () => {
|
||||
})
|
||||
dbConnection = connection
|
||||
medusaProcess = process
|
||||
|
||||
await simpleCustomerFactory(dbConnection, {
|
||||
id: "customer",
|
||||
email: "test@medusajs.com",
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
@@ -163,7 +172,11 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/order-edits", () => {
|
||||
it("gets order edit", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const response = await api.get(`/store/order-edits/${orderEditId}`)
|
||||
const response = await api.get(`/store/order-edits/${orderEditId}`, {
|
||||
headers: {
|
||||
Cookie: await getClientAuthenticationCookie(api),
|
||||
},
|
||||
})
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data.order_edit).toEqual(
|
||||
@@ -217,7 +230,14 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/order-edits", () => {
|
||||
const api = useApi()
|
||||
|
||||
const err = await api
|
||||
.get(`/store/order-edits/${orderEditId}?fields=internal_note,order_id`)
|
||||
.get(
|
||||
`/store/order-edits/${orderEditId}?fields=internal_note,order_id`,
|
||||
{
|
||||
headers: {
|
||||
Cookie: await getClientAuthenticationCookie(api),
|
||||
},
|
||||
}
|
||||
)
|
||||
.catch((e) => e)
|
||||
|
||||
expect(err.response.data.message).toBe(
|
||||
@@ -264,6 +284,11 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/order-edits", () => {
|
||||
`/store/order-edits/${declineableOrderEdit.id}/decline`,
|
||||
{
|
||||
declined_reason: "wrong color",
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Cookie: await getClientAuthenticationCookie(api),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -282,6 +307,11 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/order-edits", () => {
|
||||
`/store/order-edits/${declinedOrderEdit.id}/decline`,
|
||||
{
|
||||
declined_reason: "wrong color",
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Cookie: await getClientAuthenticationCookie(api),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -301,9 +331,17 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/order-edits", () => {
|
||||
|
||||
const api = useApi()
|
||||
await api
|
||||
.post(`/store/order-edits/${confirmedOrderEdit.id}/decline`, {
|
||||
declined_reason: "wrong color",
|
||||
})
|
||||
.post(
|
||||
`/store/order-edits/${confirmedOrderEdit.id}/decline`,
|
||||
{
|
||||
declined_reason: "wrong color",
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Cookie: await getClientAuthenticationCookie(api),
|
||||
},
|
||||
}
|
||||
)
|
||||
.catch((err) => {
|
||||
expect(err.response.status).toEqual(400)
|
||||
expect(err.response.data.message).toEqual(
|
||||
@@ -345,13 +383,16 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/order-edits", () => {
|
||||
return await db.teardown()
|
||||
})
|
||||
|
||||
// TODO once payment collection is done
|
||||
/*it("complete an order edit", async () => {})*/
|
||||
|
||||
it("idempotently complete an already confirmed order edit", async () => {
|
||||
const api = useApi()
|
||||
const result = await api.post(
|
||||
`/store/order-edits/${confirmedOrderEdit.id}/complete`
|
||||
`/store/order-edits/${confirmedOrderEdit.id}/complete`,
|
||||
undefined,
|
||||
{
|
||||
headers: {
|
||||
Cookie: await getClientAuthenticationCookie(api),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
expect(result.status).toEqual(200)
|
||||
@@ -367,7 +408,11 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/order-edits", () => {
|
||||
it("fails to complete a non requested order edit", async () => {
|
||||
const api = useApi()
|
||||
const err = await api
|
||||
.post(`/store/order-edits/${createdOrderEdit.id}/complete`)
|
||||
.post(`/store/order-edits/${createdOrderEdit.id}/complete`, undefined, {
|
||||
headers: {
|
||||
Cookie: await getClientAuthenticationCookie(api),
|
||||
},
|
||||
})
|
||||
.catch((e) => e)
|
||||
|
||||
expect(err.response.status).toEqual(400)
|
||||
|
||||
@@ -5,6 +5,9 @@ const startServerWithEnvironment =
|
||||
const { useApi } = require("../../../helpers/use-api")
|
||||
const { useDb } = require("../../../helpers/use-db")
|
||||
const adminSeeder = require("../../helpers/admin-seeder")
|
||||
const {
|
||||
getClientAuthenticationCookie,
|
||||
} = require("../../helpers/client-authentication")
|
||||
|
||||
const {
|
||||
simplePaymentCollectionFactory,
|
||||
@@ -28,6 +31,11 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/payment-collections", () => {
|
||||
})
|
||||
dbConnection = connection
|
||||
medusaProcess = process
|
||||
|
||||
await simpleCustomerFactory(dbConnection, {
|
||||
id: "customer",
|
||||
email: "test@medusajs.com",
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
@@ -71,7 +79,7 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/payment-collections", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("Manage Payment Sessions", () => {
|
||||
describe("Manage a Single Payment Session", () => {
|
||||
beforeEach(async () => {
|
||||
await adminSeeder(dbConnection)
|
||||
|
||||
@@ -97,10 +105,106 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/payment-collections", () => {
|
||||
const response = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions`,
|
||||
{
|
||||
sessions: {
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
amount: 10000,
|
||||
provider_id: "test-pay",
|
||||
}
|
||||
)
|
||||
|
||||
expect(response.data.payment_collection).toEqual(
|
||||
expect.objectContaining({
|
||||
id: payCol.id,
|
||||
type: "order_edit",
|
||||
amount: 10000,
|
||||
payment_sessions: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
amount: 10000,
|
||||
status: "pending",
|
||||
}),
|
||||
]),
|
||||
})
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
})
|
||||
|
||||
it("update a payment session", async () => {
|
||||
const api = useApi()
|
||||
|
||||
let response = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions`,
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
}
|
||||
)
|
||||
|
||||
expect(response.data.payment_collection.payment_sessions).toHaveLength(1)
|
||||
|
||||
const paySessions = response.data.payment_collection.payment_sessions
|
||||
response = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions`,
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
}
|
||||
)
|
||||
|
||||
expect(response.data.payment_collection.payment_sessions).toHaveLength(1)
|
||||
expect(response.data.payment_collection).toEqual(
|
||||
expect.objectContaining({
|
||||
id: payCol.id,
|
||||
type: "order_edit",
|
||||
amount: 10000,
|
||||
payment_sessions: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: paySessions[0].id,
|
||||
amount: 10000,
|
||||
status: "pending",
|
||||
}),
|
||||
]),
|
||||
})
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
})
|
||||
})
|
||||
|
||||
describe("Manage Multiple Payment Sessions", () => {
|
||||
beforeEach(async () => {
|
||||
await adminSeeder(dbConnection)
|
||||
|
||||
payCol = await simplePaymentCollectionFactory(dbConnection, {
|
||||
description: "paycol description",
|
||||
amount: 10000,
|
||||
})
|
||||
|
||||
await simpleCustomerFactory(dbConnection, {
|
||||
id: "customer",
|
||||
email: "test@customer.com",
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
const db = useDb()
|
||||
return await db.teardown()
|
||||
})
|
||||
|
||||
it("Set a payment session", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const response = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions/batch`,
|
||||
{
|
||||
sessions: [
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
amount: 10000,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Cookie: await getClientAuthenticationCookie(
|
||||
api,
|
||||
"test@customer.com"
|
||||
),
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -126,22 +230,19 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/payment-collections", () => {
|
||||
const api = useApi()
|
||||
|
||||
const response = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions`,
|
||||
`/store/payment-collections/${payCol.id}/sessions/batch`,
|
||||
{
|
||||
sessions: [
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
amount: 2000,
|
||||
},
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
amount: 5000,
|
||||
},
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
amount: 3000,
|
||||
},
|
||||
],
|
||||
@@ -178,22 +279,19 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/payment-collections", () => {
|
||||
const api = useApi()
|
||||
|
||||
let response = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions`,
|
||||
`/store/payment-collections/${payCol.id}/sessions/batch`,
|
||||
{
|
||||
sessions: [
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
amount: 2000,
|
||||
},
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
amount: 5000,
|
||||
},
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
amount: 3000,
|
||||
},
|
||||
],
|
||||
@@ -205,18 +303,16 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/payment-collections", () => {
|
||||
const multipleSessions = response.data.payment_collection.payment_sessions
|
||||
|
||||
response = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions`,
|
||||
`/store/payment-collections/${payCol.id}/sessions/batch`,
|
||||
{
|
||||
sessions: [
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
amount: 5000,
|
||||
session_id: multipleSessions[0].id,
|
||||
},
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
amount: 5000,
|
||||
session_id: multipleSessions[1].id,
|
||||
},
|
||||
@@ -249,7 +345,7 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/payment-collections", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("Authorize a Payment Sessions", () => {
|
||||
describe("Authorize Payment Sessions", () => {
|
||||
beforeEach(async () => {
|
||||
await adminSeeder(dbConnection)
|
||||
|
||||
@@ -269,19 +365,62 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/payment-collections", () => {
|
||||
return await db.teardown()
|
||||
})
|
||||
|
||||
it("Authorize a payment session", async () => {
|
||||
it("Authorizes a payment session", async () => {
|
||||
const api = useApi()
|
||||
|
||||
await api.post(`/store/payment-collections/${payCol.id}/sessions`, {
|
||||
sessions: {
|
||||
provider_id: "test-pay",
|
||||
customer_id: "customer",
|
||||
const payColRes = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions/batch`,
|
||||
{
|
||||
sessions: [
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
amount: 10000,
|
||||
},
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
const sessionId = payColRes.data.payment_collection.payment_sessions[0].id
|
||||
const response = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions/${sessionId}/authorize`
|
||||
)
|
||||
|
||||
expect(response.data.payment_session).toEqual(
|
||||
expect.objectContaining({
|
||||
amount: 10000,
|
||||
},
|
||||
})
|
||||
status: "authorized",
|
||||
})
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
})
|
||||
|
||||
it("Authorize multiple payment sessions", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const payColRes = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/sessions/batch`,
|
||||
{
|
||||
sessions: [
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
amount: 5000,
|
||||
},
|
||||
{
|
||||
provider_id: "test-pay",
|
||||
amount: 5000,
|
||||
},
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
const response = await api.post(
|
||||
`/store/payment-collections/${payCol.id}/authorize`
|
||||
`/store/payment-collections/${payCol.id}/sessions/batch/authorize`,
|
||||
{
|
||||
session_ids: payColRes.data.payment_collection.payment_sessions.map(
|
||||
({ id }) => id
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
expect(response.data.payment_collection).toEqual(
|
||||
@@ -291,14 +430,18 @@ describe("[MEDUSA_FF_ORDER_EDITING] /store/payment-collections", () => {
|
||||
amount: 10000,
|
||||
payment_sessions: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
amount: 10000,
|
||||
amount: 5000,
|
||||
status: "authorized",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
amount: 5000,
|
||||
status: "authorized",
|
||||
}),
|
||||
]),
|
||||
})
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.status).toEqual(207)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -19,3 +19,6 @@ export * from "./simple-batch-job-factory"
|
||||
export * from "./simple-sales-channel-factory"
|
||||
export * from "./simple-custom-shipping-option-factory"
|
||||
export * from "./simple-payment-collection-factory"
|
||||
export * from "./simple-order-edit-factory"
|
||||
export * from "./simple-order-item-change-factory"
|
||||
export * from "./simple-customer-factory"
|
||||
|
||||
@@ -11,6 +11,7 @@ export type CustomerFactoryData = {
|
||||
email?: string
|
||||
groups?: CustomerGroupFactoryData[]
|
||||
password_hash?: string
|
||||
has_account?: boolean
|
||||
}
|
||||
|
||||
export const simpleCustomerFactory = async (
|
||||
@@ -28,6 +29,10 @@ export const simpleCustomerFactory = async (
|
||||
const c = manager.create(Customer, {
|
||||
id: customerId,
|
||||
email: data.email,
|
||||
password_hash:
|
||||
data.password_hash ??
|
||||
"c2NyeXB0AAEAAAABAAAAAVMdaddoGjwU1TafDLLlBKnOTQga7P2dbrfgf3fB+rCD/cJOMuGzAvRdKutbYkVpuJWTU39P7OpuWNkUVoEETOVLMJafbI8qs8Qx/7jMQXkN", // password matching "test"
|
||||
has_account: data.has_account ?? true,
|
||||
})
|
||||
|
||||
if (data.password_hash) {
|
||||
|
||||
20
integration-tests/api/helpers/client-authentication.ts
Normal file
20
integration-tests/api/helpers/client-authentication.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
const AUTH_COOKIE = {}
|
||||
export async function getClientAuthenticationCookie(
|
||||
api,
|
||||
email = null,
|
||||
password = null
|
||||
) {
|
||||
const user = {
|
||||
email: email ?? "test@medusajs.com",
|
||||
password: password ?? "test",
|
||||
}
|
||||
|
||||
if (AUTH_COOKIE[user.email]) {
|
||||
return AUTH_COOKIE[user.email]
|
||||
}
|
||||
|
||||
const authResponse = await api.post("/store/auth", user)
|
||||
AUTH_COOKIE[user.email] = authResponse.headers["set-cookie"][0].split(";")
|
||||
|
||||
return AUTH_COOKIE[user.email]
|
||||
}
|
||||
@@ -13,6 +13,7 @@ export const MedusaErrorTypes = {
|
||||
NOT_ALLOWED: "not_allowed",
|
||||
UNEXPECTED_STATE: "unexpected_state",
|
||||
CONFLICT: "conflict",
|
||||
PAYMENT_AUTHORIZATION_ERROR: "payment_authorization_error",
|
||||
}
|
||||
|
||||
export const MedusaErrorCodes = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
AdminUpdatePaymentCollectionRequest,
|
||||
AdminUpdatePaymentCollectionsReq,
|
||||
AdminPaymentCollectionDeleteRes,
|
||||
AdminPaymentCollectionRes,
|
||||
AdminPaymentCollectionsRes,
|
||||
GetPaymentCollectionsParams,
|
||||
} from "@medusajs/medusa"
|
||||
import { ResponsePromise } from "../../typings"
|
||||
@@ -13,7 +13,7 @@ class AdminPaymentCollectionsResource extends BaseResource {
|
||||
id: string,
|
||||
query?: GetPaymentCollectionsParams,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminPaymentCollectionRes> {
|
||||
): ResponsePromise<AdminPaymentCollectionsRes> {
|
||||
let path = `/admin/payment-collections/${id}`
|
||||
|
||||
if (query) {
|
||||
@@ -26,9 +26,9 @@ class AdminPaymentCollectionsResource extends BaseResource {
|
||||
|
||||
update(
|
||||
id: string,
|
||||
payload: AdminUpdatePaymentCollectionRequest,
|
||||
payload: AdminUpdatePaymentCollectionsReq,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminPaymentCollectionRes> {
|
||||
): ResponsePromise<AdminPaymentCollectionsRes> {
|
||||
const path = `/admin/payment-collections/${id}`
|
||||
return this.client.request("POST", path, payload, {}, customHeaders)
|
||||
}
|
||||
@@ -44,7 +44,7 @@ class AdminPaymentCollectionsResource extends BaseResource {
|
||||
markAsAuthorized(
|
||||
id: string,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminPaymentCollectionRes> {
|
||||
): ResponsePromise<AdminPaymentCollectionsRes> {
|
||||
const path = `/admin/payment-collections/${id}/authorize`
|
||||
return this.client.request("POST", path, undefined, {}, customHeaders)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import {
|
||||
GetPaymentCollectionsParams,
|
||||
StoreManagePaymentCollectionSessionRequest,
|
||||
StoreRefreshPaymentCollectionSessionRequest,
|
||||
StorePaymentCollectionSessionRes,
|
||||
StorePaymentCollectionRes,
|
||||
StorePostPaymentCollectionsBatchSessionsReq,
|
||||
StorePostPaymentCollectionsBatchSessionsAuthorizeReq,
|
||||
StorePaymentCollectionSessionsReq,
|
||||
StorePaymentCollectionsSessionRes,
|
||||
StorePaymentCollectionsRes,
|
||||
} from "@medusajs/medusa"
|
||||
import { ResponsePromise } from "../typings"
|
||||
import BaseResource from "./base"
|
||||
@@ -14,7 +15,7 @@ class PaymentCollectionsResource extends BaseResource {
|
||||
id: string,
|
||||
query?: GetPaymentCollectionsParams,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<StorePaymentCollectionRes> {
|
||||
): ResponsePromise<StorePaymentCollectionsRes> {
|
||||
let path = `/store/payment-collections/${id}`
|
||||
|
||||
if (query) {
|
||||
@@ -25,19 +26,38 @@ class PaymentCollectionsResource extends BaseResource {
|
||||
return this.client.request("GET", path, undefined, {}, customHeaders)
|
||||
}
|
||||
|
||||
authorize(
|
||||
authorizePaymentSession(
|
||||
id: string,
|
||||
session_id: string,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<StorePaymentCollectionRes> {
|
||||
const path = `/store/payment-collections/${id}/authorize`
|
||||
): ResponsePromise<StorePaymentCollectionsRes> {
|
||||
const path = `/store/payment-collections/${id}/sessions/${session_id}/authorize`
|
||||
return this.client.request("POST", path, undefined, {}, customHeaders)
|
||||
}
|
||||
|
||||
manageSessions(
|
||||
authorizePaymentSessionsBatch(
|
||||
id: string,
|
||||
payload: StoreManagePaymentCollectionSessionRequest,
|
||||
payload: StorePostPaymentCollectionsBatchSessionsAuthorizeReq,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<StorePaymentCollectionRes> {
|
||||
): ResponsePromise<StorePaymentCollectionsRes> {
|
||||
const path = `/store/payment-collections/${id}/sessions/batch/authorize`
|
||||
return this.client.request("POST", path, payload, {}, customHeaders)
|
||||
}
|
||||
|
||||
managePaymentSessionsBatch(
|
||||
id: string,
|
||||
payload: StorePostPaymentCollectionsBatchSessionsReq,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<StorePaymentCollectionsRes> {
|
||||
const path = `/store/payment-collections/${id}/sessions/batch`
|
||||
return this.client.request("POST", path, payload, {}, customHeaders)
|
||||
}
|
||||
|
||||
managePaymentSession(
|
||||
id: string,
|
||||
payload: StorePaymentCollectionSessionsReq,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<StorePaymentCollectionsRes> {
|
||||
const path = `/store/payment-collections/${id}/sessions`
|
||||
return this.client.request("POST", path, payload, {}, customHeaders)
|
||||
}
|
||||
@@ -45,11 +65,10 @@ class PaymentCollectionsResource extends BaseResource {
|
||||
refreshPaymentSession(
|
||||
id: string,
|
||||
session_id: string,
|
||||
payload: StoreRefreshPaymentCollectionSessionRequest,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<StorePaymentCollectionSessionRes> {
|
||||
const path = `/store/payment-collections/${id}/sessions/${session_id}/refresh`
|
||||
return this.client.request("POST", path, payload, {}, customHeaders)
|
||||
): ResponsePromise<StorePaymentCollectionsSessionRes> {
|
||||
const path = `/store/payment-collections/${id}/sessions/${session_id}`
|
||||
return this.client.request("POST", path, undefined, {}, customHeaders)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ export default async (req, res) => {
|
||||
async function autorizePaymentCollection(req, id, orderId) {
|
||||
const manager = req.scope.resolve("manager")
|
||||
const paymentCollectionService = req.scope.resolve(
|
||||
"paymentCollectonService"
|
||||
"paymentCollectionService"
|
||||
)
|
||||
|
||||
await manager.transaction(async (manager) => {
|
||||
|
||||
@@ -181,7 +181,7 @@ class StripeProviderService extends AbstractPaymentService {
|
||||
|
||||
async createPaymentNew(paymentInput, intentRequestData = {}) {
|
||||
const { customer, currency_code, amount, resource_id, cart } = paymentInput
|
||||
const { id: customer_id, email } = customer
|
||||
const { id: customer_id, email } = customer ?? {}
|
||||
|
||||
const intentRequest = {
|
||||
description:
|
||||
@@ -205,7 +205,7 @@ class StripeProviderService extends AbstractPaymentService {
|
||||
|
||||
intentRequest.customer = stripeCustomer.id
|
||||
}
|
||||
} else {
|
||||
} else if (email) {
|
||||
const stripeCustomer = await this.createCustomer({
|
||||
email,
|
||||
})
|
||||
@@ -302,7 +302,7 @@ class StripeProviderService extends AbstractPaymentService {
|
||||
try {
|
||||
const stripeId = paymentInput.customer?.metadata?.stripe_id
|
||||
|
||||
if (stripeId !== paymentInput.customer_id) {
|
||||
if (stripeId !== paymentSessionData.customer) {
|
||||
return await this.createPaymentNew(paymentInput, intentRequestData)
|
||||
} else {
|
||||
if (paymentSessionData.amount === Math.round(paymentInput.amount)) {
|
||||
|
||||
@@ -1154,8 +1154,8 @@
|
||||
"publishable_api_key": {
|
||||
"id": "pubkey_1234",
|
||||
"created_by": "admin_user",
|
||||
"created_at": "2021-11-08 11:58:56.975971+01",
|
||||
"updated_at": "2021-11-08 11:58:56.975971+01",
|
||||
"created_at": "2021-11-08 11:58:56.975971+01",
|
||||
"updated_at": "2021-11-08 11:58:56.975971+01",
|
||||
"revoked_by": null,
|
||||
"revoked_at": null
|
||||
},
|
||||
@@ -1324,6 +1324,76 @@
|
||||
"created_at": "2022-07-05T15:16:01.959Z",
|
||||
"deleted_at": null
|
||||
}
|
||||
]
|
||||
],
|
||||
"payment_collection": {
|
||||
"id": "paycol_01GJK7P9MRHM6XWCJG70JFB8PF",
|
||||
"created_at": "2022-11-23T21:53:19.367Z",
|
||||
"updated_at": "2022-11-24T12:57:08.652Z",
|
||||
"deleted_at": null,
|
||||
"type": "order_edit",
|
||||
"status": "authorized",
|
||||
"description": null,
|
||||
"amount": 900,
|
||||
"authorized_amount": 900,
|
||||
"region_id": "test-region",
|
||||
"currency_code": "usd",
|
||||
"metadata": null,
|
||||
"created_by": "admin_user",
|
||||
"payment_sessions": [
|
||||
{
|
||||
"id": "ps_01GJMVD71Z4WF9FXXGT7DHGPCM",
|
||||
"created_at": "2022-11-24T12:57:07.883Z",
|
||||
"updated_at": "2022-11-24T12:57:08.652Z",
|
||||
"cart_id": null,
|
||||
"provider_id": "test-pay",
|
||||
"is_selected": null,
|
||||
"status": "authorized",
|
||||
"data": {},
|
||||
"idempotency_key": null,
|
||||
"amount": 900,
|
||||
"payment_authorized_at": "2022-11-24T12:57:08.672Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
"payment_sessions": {
|
||||
"id": "ps_01GJMVD71Z4WF9FXXGT7DHGPCM",
|
||||
"created_at": "2022-11-24T12:57:07.883Z",
|
||||
"updated_at": "2022-11-24T12:57:08.652Z",
|
||||
"cart_id": null,
|
||||
"provider_id": "test-pay",
|
||||
"is_selected": null,
|
||||
"status": "authorized",
|
||||
"data": {},
|
||||
"idempotency_key": null,
|
||||
"amount": 900,
|
||||
"payment_authorized_at": "2022-11-24T12:57:08.672Z"
|
||||
},
|
||||
"payment": {
|
||||
"id": "pay_A1GJEVD71Z4WF9FXFGT7D1GP15",
|
||||
"swap_id": null,
|
||||
"cart_id": null,
|
||||
"order_id": null,
|
||||
"amount": 900,
|
||||
"currency_code": "usd",
|
||||
"amount_refunded": 0,
|
||||
"amount_captured": 900,
|
||||
"provider_id": "manual",
|
||||
"data": {},
|
||||
"captured_at": "2022-11-17T21:24:35.871Z",
|
||||
"canceled_at": null,
|
||||
"created_at": "2022-11-16T21:24:35.871Z",
|
||||
"updated_at": "2022-11-16T21:24:35.871Z",
|
||||
"metadata": null,
|
||||
"idempotency_key": null
|
||||
},
|
||||
"refund": {
|
||||
"order_id": null,
|
||||
"payment_id": "pay_A1GJEVD71Z4WF9FXFGT7D1GP15",
|
||||
"amount": 900,
|
||||
"note": null,
|
||||
"reason": "return",
|
||||
"metadata": null,
|
||||
"idempotency_key": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2104,4 +2104,103 @@ export const adminHandlers = [
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.get("/admin/payment-collections/:id", (req, res, ctx) => {
|
||||
const { id } = req.params
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
payment_collection: {
|
||||
...fixtures.get("payment_collection"),
|
||||
id,
|
||||
},
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.delete("/admin/payment-collections/:id", (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
id: req.params.id,
|
||||
object: "payment_collection",
|
||||
deleted: true,
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.post("/admin/payment-collections/:id", (req, res, ctx) => {
|
||||
const { id } = req.params
|
||||
const { description, metadata } = req.body as any
|
||||
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
payment_collection: {
|
||||
...fixtures.get("payment_collection"),
|
||||
description,
|
||||
metadata,
|
||||
id,
|
||||
},
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.post("/admin/payment-collections/:id/authorize", (req, res, ctx) => {
|
||||
const { id } = req.params
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
payment_collection: {
|
||||
...fixtures.get("payment_collection"),
|
||||
id,
|
||||
},
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.get("/admin/payments/:id", (req, res, ctx) => {
|
||||
const { id } = req.params
|
||||
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
payment: {
|
||||
...fixtures.get("payment"),
|
||||
id,
|
||||
},
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.post("/admin/payments/:id/capture", (req, res, ctx) => {
|
||||
const { id } = req.params
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
payment: {
|
||||
...fixtures.get("payment"),
|
||||
id,
|
||||
},
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.post("/admin/payments/:id/refund", (req, res, ctx) => {
|
||||
const { id } = req.params
|
||||
const { amount, reason, note } = req.body as any
|
||||
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
refund: {
|
||||
...fixtures.get("refund"),
|
||||
payment_id: id,
|
||||
amount,
|
||||
reason,
|
||||
note,
|
||||
},
|
||||
})
|
||||
)
|
||||
}),
|
||||
]
|
||||
|
||||
@@ -446,4 +446,100 @@ export const storeHandlers = [
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.get("/store/payment-collections/:id", (req, res, ctx) => {
|
||||
const { id } = req.params
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
payment_collection: {
|
||||
...fixtures.get("payment_collection"),
|
||||
id,
|
||||
},
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.post(
|
||||
"/store/payment-collections/:id/sessions/batch",
|
||||
(req, res, ctx) => {
|
||||
const { id } = req.params
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
payment_collection: {
|
||||
...fixtures.get("payment_collection"),
|
||||
id,
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
),
|
||||
|
||||
rest.post(
|
||||
"/store/payment-collections/:id/sessions/batch/authorize",
|
||||
(req, res, ctx) => {
|
||||
const { id } = req.params
|
||||
return res(
|
||||
ctx.status(207),
|
||||
ctx.json({
|
||||
payment_collection: {
|
||||
...fixtures.get("payment_collection"),
|
||||
id,
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
),
|
||||
|
||||
rest.post("/store/payment-collections/:id/sessions", (req, res, ctx) => {
|
||||
const { id } = req.params
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
payment_collection: {
|
||||
...fixtures.get("payment_collection"),
|
||||
id,
|
||||
},
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.post(
|
||||
"/store/payment-collections/:id/sessions/:session_id",
|
||||
(req, res, ctx) => {
|
||||
const { id, session_id } = req.params
|
||||
const payCol: any = { ...fixtures.get("payment_collection") }
|
||||
|
||||
payCol.payment_sessions[0].id = `new_${session_id}`
|
||||
const session = {
|
||||
payment_session: payCol.payment_sessions[0],
|
||||
}
|
||||
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
...session,
|
||||
})
|
||||
)
|
||||
}
|
||||
),
|
||||
|
||||
rest.post(
|
||||
"/store/payment-collections/:id/sessions/:session_id/authorize",
|
||||
(req, res, ctx) => {
|
||||
const { session_id } = req.params
|
||||
|
||||
const session = fixtures.get("payment_collection").payment_sessions[0]
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
payment_session: {
|
||||
...session,
|
||||
id: session_id,
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
),
|
||||
]
|
||||
|
||||
@@ -30,3 +30,5 @@ export * from "./tax-rates"
|
||||
export * from "./uploads"
|
||||
export * from "./users"
|
||||
export * from "./variants"
|
||||
export * from "./payment-collections"
|
||||
export * from "./payments"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./queries"
|
||||
export * from "./mutations"
|
||||
@@ -0,0 +1,85 @@
|
||||
import { useMutation, UseMutationOptions, useQueryClient } from "react-query"
|
||||
import { Response } from "@medusajs/medusa-js"
|
||||
|
||||
import {
|
||||
AdminPaymentCollectionDeleteRes,
|
||||
AdminPaymentCollectionsRes,
|
||||
AdminUpdatePaymentCollectionsReq,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
import { buildOptions } from "../../utils/buildOptions"
|
||||
import { useMedusa } from "../../../contexts"
|
||||
import { adminPaymentCollectionQueryKeys } from "."
|
||||
|
||||
export const useAdminDeletePaymentCollection = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<AdminPaymentCollectionDeleteRes>,
|
||||
Error,
|
||||
void
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(
|
||||
() => client.admin.paymentCollections.delete(id),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[
|
||||
adminPaymentCollectionQueryKeys.detail(id),
|
||||
adminPaymentCollectionQueryKeys.lists(),
|
||||
],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export const useAdminUpdatePaymentCollection = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<AdminPaymentCollectionsRes>,
|
||||
Error,
|
||||
AdminUpdatePaymentCollectionsReq
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(
|
||||
(payload: AdminUpdatePaymentCollectionsReq) =>
|
||||
client.admin.paymentCollections.update(id, payload),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[
|
||||
adminPaymentCollectionQueryKeys.detail(id),
|
||||
adminPaymentCollectionQueryKeys.lists(),
|
||||
],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export const useAdminMarkPaymentCollectionAsAuthorized = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<AdminPaymentCollectionsRes>,
|
||||
Error,
|
||||
void
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(
|
||||
() => client.admin.paymentCollections.markAsAuthorized(id),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[
|
||||
adminPaymentCollectionQueryKeys.detail(id),
|
||||
adminPaymentCollectionQueryKeys.lists(),
|
||||
],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { queryKeysFactory } from "../../utils"
|
||||
import { AdminPaymentCollectionsRes } from "@medusajs/medusa"
|
||||
import { useQuery } from "react-query"
|
||||
import { useMedusa } from "../../../contexts"
|
||||
import { UseQueryOptionsWrapper } from "../../../types"
|
||||
import { Response } from "@medusajs/medusa-js"
|
||||
|
||||
const PAYMENT_COLLECTION_QUERY_KEY = `paymentCollection` as const
|
||||
|
||||
export const adminPaymentCollectionQueryKeys = queryKeysFactory<
|
||||
typeof PAYMENT_COLLECTION_QUERY_KEY
|
||||
>(PAYMENT_COLLECTION_QUERY_KEY)
|
||||
|
||||
type AdminPaymentCollectionKey = typeof adminPaymentCollectionQueryKeys
|
||||
|
||||
export const useAdminPaymentCollection = (
|
||||
id: string,
|
||||
options?: UseQueryOptionsWrapper<
|
||||
Response<AdminPaymentCollectionsRes>,
|
||||
Error,
|
||||
ReturnType<AdminPaymentCollectionKey["detail"]>
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const { data, ...rest } = useQuery(
|
||||
adminPaymentCollectionQueryKeys.detail(id),
|
||||
() => client.admin.paymentCollections.retrieve(id),
|
||||
options
|
||||
)
|
||||
|
||||
return { ...data, ...rest } as const
|
||||
}
|
||||
2
packages/medusa-react/src/hooks/admin/payments/index.ts
Normal file
2
packages/medusa-react/src/hooks/admin/payments/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./queries"
|
||||
export * from "./mutations"
|
||||
51
packages/medusa-react/src/hooks/admin/payments/mutations.ts
Normal file
51
packages/medusa-react/src/hooks/admin/payments/mutations.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { useMutation, UseMutationOptions, useQueryClient } from "react-query"
|
||||
import { Response } from "@medusajs/medusa-js"
|
||||
|
||||
import {
|
||||
AdminPaymentRes,
|
||||
AdminPostPaymentRefundsReq,
|
||||
AdminRefundRes,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
import { buildOptions } from "../../utils/buildOptions"
|
||||
import { useMedusa } from "../../../contexts"
|
||||
import { adminPaymentQueryKeys } from "."
|
||||
|
||||
export const useAdminPaymentsCapturePayment = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<Response<AdminPaymentRes>, Error, void>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(
|
||||
() => client.admin.payments.capturePayment(id),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[adminPaymentQueryKeys.detail(id), adminPaymentQueryKeys.lists()],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export const useAdminPaymentsRefundPayment = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<AdminRefundRes>,
|
||||
Error,
|
||||
AdminPostPaymentRefundsReq
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(
|
||||
(payload: AdminPostPaymentRefundsReq) =>
|
||||
client.admin.payments.refundPayment(id, payload),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[adminPaymentQueryKeys.detail(id), adminPaymentQueryKeys.lists()],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
31
packages/medusa-react/src/hooks/admin/payments/queries.ts
Normal file
31
packages/medusa-react/src/hooks/admin/payments/queries.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { queryKeysFactory } from "../../utils"
|
||||
import { AdminPaymentRes } from "@medusajs/medusa"
|
||||
import { useQuery } from "react-query"
|
||||
import { useMedusa } from "../../../contexts"
|
||||
import { UseQueryOptionsWrapper } from "../../../types"
|
||||
import { Response } from "@medusajs/medusa-js"
|
||||
|
||||
const PAYMENT_QUERY_KEY = `payment` as const
|
||||
|
||||
export const adminPaymentQueryKeys =
|
||||
queryKeysFactory<typeof PAYMENT_QUERY_KEY>(PAYMENT_QUERY_KEY)
|
||||
|
||||
type AdminPaymentKey = typeof adminPaymentQueryKeys
|
||||
|
||||
export const useAdminPayment = (
|
||||
id: string,
|
||||
options?: UseQueryOptionsWrapper<
|
||||
Response<AdminPaymentRes>,
|
||||
Error,
|
||||
ReturnType<AdminPaymentKey["detail"]>
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const { data, ...rest } = useQuery(
|
||||
adminPaymentQueryKeys.detail(id),
|
||||
() => client.admin.payments.retrieve(id),
|
||||
options
|
||||
)
|
||||
|
||||
return { ...data, ...rest } as const
|
||||
}
|
||||
@@ -13,3 +13,4 @@ export * from "./returns/"
|
||||
export * from "./gift-cards/"
|
||||
export * from "./line-items/"
|
||||
export * from "./collections"
|
||||
export * from "./payment-collections"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./queries"
|
||||
export * from "./mutations"
|
||||
@@ -0,0 +1,139 @@
|
||||
import { useMutation, UseMutationOptions, useQueryClient } from "react-query"
|
||||
import { Response } from "@medusajs/medusa-js"
|
||||
|
||||
import {
|
||||
StorePaymentCollectionsRes,
|
||||
StorePostPaymentCollectionsBatchSessionsReq,
|
||||
StorePostPaymentCollectionsBatchSessionsAuthorizeReq,
|
||||
StorePaymentCollectionSessionsReq,
|
||||
StorePaymentCollectionsSessionRes,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
import { buildOptions } from "../../utils/buildOptions"
|
||||
import { useMedusa } from "../../../contexts"
|
||||
import { paymentCollectionQueryKeys } from "."
|
||||
|
||||
export const useManageMultiplePaymentSessions = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<StorePaymentCollectionsRes>,
|
||||
Error,
|
||||
StorePostPaymentCollectionsBatchSessionsReq
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(
|
||||
(payload: StorePostPaymentCollectionsBatchSessionsReq) =>
|
||||
client.paymentCollections.managePaymentSessionsBatch(id, payload),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[
|
||||
paymentCollectionQueryKeys.lists(),
|
||||
paymentCollectionQueryKeys.detail(id),
|
||||
],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export const useManagePaymentSession = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<StorePaymentCollectionsRes>,
|
||||
Error,
|
||||
StorePaymentCollectionSessionsReq
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(
|
||||
(payload: StorePaymentCollectionSessionsReq) =>
|
||||
client.paymentCollections.managePaymentSession(id, payload),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[
|
||||
paymentCollectionQueryKeys.lists(),
|
||||
paymentCollectionQueryKeys.detail(id),
|
||||
],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export const useAuthorizePaymentSession = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<StorePaymentCollectionsRes>,
|
||||
Error,
|
||||
string
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(
|
||||
(session_id: string) =>
|
||||
client.paymentCollections.authorizePaymentSession(id, session_id),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[
|
||||
paymentCollectionQueryKeys.lists(),
|
||||
paymentCollectionQueryKeys.detail(id),
|
||||
],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export const useAuthorizePaymentSessionsBatch = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<StorePaymentCollectionsRes>,
|
||||
Error,
|
||||
StorePostPaymentCollectionsBatchSessionsAuthorizeReq
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(
|
||||
(payload) =>
|
||||
client.paymentCollections.authorizePaymentSessionsBatch(id, payload),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[
|
||||
paymentCollectionQueryKeys.lists(),
|
||||
paymentCollectionQueryKeys.detail(id),
|
||||
],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export const usePaymentCollectionRefreshPaymentSession = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<StorePaymentCollectionsSessionRes>,
|
||||
Error,
|
||||
string
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(
|
||||
(session_id: string) =>
|
||||
client.paymentCollections.refreshPaymentSession(id, session_id),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[
|
||||
paymentCollectionQueryKeys.lists(),
|
||||
paymentCollectionQueryKeys.detail(id),
|
||||
],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { queryKeysFactory } from "../../utils"
|
||||
import { StorePaymentCollectionsRes } from "@medusajs/medusa"
|
||||
import { useQuery } from "react-query"
|
||||
import { useMedusa } from "../../../contexts"
|
||||
import { UseQueryOptionsWrapper } from "../../../types"
|
||||
import { Response } from "@medusajs/medusa-js"
|
||||
|
||||
const PAYMENT_COLLECTION_QUERY_KEY = `paymentCollection` as const
|
||||
|
||||
export const paymentCollectionQueryKeys = queryKeysFactory<
|
||||
typeof PAYMENT_COLLECTION_QUERY_KEY
|
||||
>(PAYMENT_COLLECTION_QUERY_KEY)
|
||||
|
||||
type PaymentCollectionKey = typeof paymentCollectionQueryKeys
|
||||
|
||||
export const usePaymentCollection = (
|
||||
id: string,
|
||||
options?: UseQueryOptionsWrapper<
|
||||
Response<StorePaymentCollectionsRes>,
|
||||
Error,
|
||||
ReturnType<PaymentCollectionKey["detail"]>
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const { data, ...rest } = useQuery(
|
||||
paymentCollectionQueryKeys.detail(id),
|
||||
() => client.paymentCollections.retrieve(id),
|
||||
options
|
||||
)
|
||||
|
||||
return { ...data, ...rest } as const
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import {
|
||||
useAdminDeletePaymentCollection,
|
||||
useAdminUpdatePaymentCollection,
|
||||
useAdminMarkPaymentCollectionAsAuthorized,
|
||||
} from "../../../../src"
|
||||
import { renderHook } from "@testing-library/react-hooks"
|
||||
import { createWrapper } from "../../../utils"
|
||||
|
||||
describe("useAdminDeletePaymentCollection hook", () => {
|
||||
test("Delete a payment collection", async () => {
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminDeletePaymentCollection("payment_collection_id"),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate()
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(200)
|
||||
expect(result.current.data).toEqual(
|
||||
expect.objectContaining({
|
||||
id: "payment_collection_id",
|
||||
deleted: true,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("useAdminUpdatePaymentCollection hook", () => {
|
||||
test("Update a Payment Collection", async () => {
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminUpdatePaymentCollection("payment_collection_id"),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate({
|
||||
description: "new description",
|
||||
metadata: { demo: "obj" },
|
||||
})
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(200)
|
||||
expect(result.current.data.payment_collection).toEqual(
|
||||
expect.objectContaining({
|
||||
id: "payment_collection_id",
|
||||
description: "new description",
|
||||
metadata: { demo: "obj" },
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("useAdminMarkPaymentCollectionAsAuthorized hook", () => {
|
||||
test("Mark a Payment Collection as Authorized", async () => {
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminMarkPaymentCollectionAsAuthorized("payment_collection_id"),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate()
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(200)
|
||||
expect(result.current.data.payment_collection).toEqual(
|
||||
expect.objectContaining({
|
||||
id: "payment_collection_id",
|
||||
status: "authorized",
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,21 @@
|
||||
import { renderHook } from "@testing-library/react-hooks"
|
||||
import { fixtures } from "../../../../mocks/data"
|
||||
import { createWrapper } from "../../../utils"
|
||||
import { useAdminPaymentCollection } from "../../../../src/hooks/admin/payment-collections"
|
||||
|
||||
describe("useAdminPaymentCollection hook", () => {
|
||||
test("returns a payment collection", async () => {
|
||||
const payment_collection = fixtures.get("payment_collection")
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminPaymentCollection(payment_collection.id),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.response.status).toEqual(200)
|
||||
expect(result.current.payment_collection).toEqual(payment_collection)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,58 @@
|
||||
import {
|
||||
useAdminPaymentsCapturePayment,
|
||||
useAdminPaymentsRefundPayment,
|
||||
} from "../../../../src"
|
||||
import { renderHook } from "@testing-library/react-hooks"
|
||||
import { createWrapper } from "../../../utils"
|
||||
import { RefundReason } from "@medusajs/medusa"
|
||||
|
||||
describe("useAdminPaymentsCapturePayment hook", () => {
|
||||
test("Capture a payment", async () => {
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminPaymentsCapturePayment("payment_id"),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate()
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(200)
|
||||
expect(result.current.data.payment).toEqual(
|
||||
expect.objectContaining({
|
||||
amount_captured: 900,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("useAdminPaymentsRefundPayment hook", () => {
|
||||
test("Update a Payment Collection", async () => {
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminPaymentsRefundPayment("payment_id"),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate({
|
||||
amount: 500,
|
||||
reason: RefundReason.DISCOUNT,
|
||||
note: "note to refund",
|
||||
})
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(200)
|
||||
expect(result.current.data.refund).toEqual(
|
||||
expect.objectContaining({
|
||||
payment_id: "payment_id",
|
||||
amount: 500,
|
||||
reason: RefundReason.DISCOUNT,
|
||||
note: "note to refund",
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
import { renderHook } from "@testing-library/react-hooks"
|
||||
import { fixtures } from "../../../../mocks/data"
|
||||
import { createWrapper } from "../../../utils"
|
||||
import { useAdminPayment } from "../../../../src/hooks/admin/payments"
|
||||
|
||||
describe("useAdminPayment hook", () => {
|
||||
test("returns a payment collection", async () => {
|
||||
const payment = fixtures.get("payment")
|
||||
const { result, waitFor } = renderHook(() => useAdminPayment(payment.id), {
|
||||
wrapper: createWrapper(),
|
||||
})
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.response.status).toEqual(200)
|
||||
expect(result.current.payment).toEqual(payment)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,138 @@
|
||||
import {
|
||||
useManageMultiplePaymentSessions,
|
||||
useManagePaymentSession,
|
||||
useAuthorizePaymentSession,
|
||||
useAuthorizePaymentSessionsBatch,
|
||||
usePaymentCollectionRefreshPaymentSession,
|
||||
} from "../../../../src"
|
||||
import { renderHook } from "@testing-library/react-hooks"
|
||||
import { createWrapper } from "../../../utils"
|
||||
|
||||
describe("useManageMultiplePaymentSessions hook", () => {
|
||||
test("Manage multiple payment sessions of a payment collection", async () => {
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useManageMultiplePaymentSessions("payment_collection_id"),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate({
|
||||
sessions: {
|
||||
provider_id: "manual",
|
||||
amount: 900,
|
||||
},
|
||||
})
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(200)
|
||||
expect(result.current.data?.payment_collection).toEqual(
|
||||
expect.objectContaining({
|
||||
id: "payment_collection_id",
|
||||
amount: 900,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("useManagePaymentSession hook", () => {
|
||||
test("Manage payment session of a payment collection", async () => {
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useManagePaymentSession("payment_collection_id"),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate({
|
||||
provider_id: "manual",
|
||||
})
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(200)
|
||||
expect(result.current.data?.payment_collection).toEqual(
|
||||
expect.objectContaining({
|
||||
id: "payment_collection_id",
|
||||
amount: 900,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("useAuthorizePaymentSession hook", () => {
|
||||
test("Authorize a payment session of a Payment Collection", async () => {
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAuthorizePaymentSession("payment_collection_id"),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate("123")
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(200)
|
||||
expect(result.current.data.payment_session).toEqual(
|
||||
expect.objectContaining({
|
||||
id: "123",
|
||||
amount: 900,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("authorizePaymentSessionsBatch hook", () => {
|
||||
test("Authorize all payment sessions of a Payment Collection", async () => {
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAuthorizePaymentSessionsBatch("payment_collection_id"),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate({
|
||||
session_ids: ["abc"],
|
||||
})
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(207)
|
||||
|
||||
expect(result.current.data.payment_collection).toEqual(
|
||||
expect.objectContaining({
|
||||
id: "payment_collection_id",
|
||||
payment_sessions: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
amount: 900,
|
||||
}),
|
||||
]),
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("usePaymentCollectionRefreshPaymentSession hook", () => {
|
||||
test("Refresh a payment sessions of a Payment Collection", async () => {
|
||||
const { result, waitFor } = renderHook(
|
||||
() => usePaymentCollectionRefreshPaymentSession("payment_collection_id"),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate("session_id")
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(200)
|
||||
expect(result.current.data.payment_session).toEqual(
|
||||
expect.objectContaining({
|
||||
id: "new_session_id",
|
||||
amount: 900,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,21 @@
|
||||
import { renderHook } from "@testing-library/react-hooks"
|
||||
import { fixtures } from "../../../../mocks/data"
|
||||
import { createWrapper } from "../../../utils"
|
||||
import { usePaymentCollection } from "../../../../src/hooks/store/payment-collections"
|
||||
|
||||
describe("usePaymentCollection hook", () => {
|
||||
test("returns a payment collection", async () => {
|
||||
const payment_collection = fixtures.get("payment_collection")
|
||||
const { result, waitFor } = renderHook(
|
||||
() => usePaymentCollection(payment_collection.id),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.response.status).toEqual(200)
|
||||
expect(result.current.payment_collection).toEqual(payment_collection)
|
||||
})
|
||||
})
|
||||
@@ -13,7 +13,11 @@ export default (): RequestHandler => {
|
||||
if (err) {
|
||||
return next(err)
|
||||
}
|
||||
req.user = user
|
||||
|
||||
if (user) {
|
||||
req.user = user
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
)(req, res, next)
|
||||
|
||||
@@ -46,6 +46,9 @@ export default () => {
|
||||
case MedusaError.Types.UNAUTHORIZED:
|
||||
statusCode = 401
|
||||
break
|
||||
case MedusaError.Types.PAYMENT_AUTHORIZATION_ERROR:
|
||||
statusCode = 422
|
||||
break
|
||||
case MedusaError.Types.DUPLICATE_ERROR:
|
||||
statusCode = 422
|
||||
errObj.code = INVALID_REQUEST_ERROR
|
||||
|
||||
@@ -3,6 +3,10 @@ import passport from "passport"
|
||||
|
||||
export default (): RequestHandler => {
|
||||
return (req: Request, res: Response, next: NextFunction): void => {
|
||||
if (req.user) {
|
||||
return next()
|
||||
}
|
||||
|
||||
passport.authenticate(["store-jwt", "bearer"], { session: false })(
|
||||
req,
|
||||
res,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [get] /payment-collections/{id}
|
||||
* operationId: "GetPaymentCollectonsPaymentCollection"
|
||||
* operationId: "GetPaymentCollectionsPaymentCollection"
|
||||
* summary: "Retrieve an PaymentCollection"
|
||||
* description: "Retrieves a PaymentCollection."
|
||||
* x-authenticated: true
|
||||
|
||||
@@ -8,7 +8,7 @@ import OrderEditingFeatureFlag from "../../../../loaders/feature-flags/order-edi
|
||||
import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled"
|
||||
|
||||
import { GetPaymentCollectionsParams } from "./get-payment-collection"
|
||||
import { AdminUpdatePaymentCollectionRequest } from "./update-payment-collection"
|
||||
import { AdminUpdatePaymentCollectionsReq } from "./update-payment-collection"
|
||||
import { PaymentCollection } from "../../../../models"
|
||||
|
||||
const route = Router()
|
||||
@@ -32,7 +32,7 @@ export default (app, container) => {
|
||||
|
||||
route.post(
|
||||
"/:id",
|
||||
transformBody(AdminUpdatePaymentCollectionRequest),
|
||||
transformBody(AdminUpdatePaymentCollectionsReq),
|
||||
middlewares.wrap(require("./update-payment-collection").default)
|
||||
)
|
||||
|
||||
@@ -68,7 +68,7 @@ export const defaulPaymentCollectionRelations = [
|
||||
"payments",
|
||||
]
|
||||
|
||||
export type AdminPaymentCollectionRes = {
|
||||
export type AdminPaymentCollectionsRes = {
|
||||
payment_collection: PaymentCollection
|
||||
}
|
||||
export type AdminPaymentCollectionDeleteRes = {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { PaymentCollectionService } from "../../../../services"
|
||||
|
||||
/**
|
||||
* @oas [post] /payment-collections/{id}/authorize
|
||||
* operationId: "MarkAuthorizedPaymentCollectionsPaymentCollection"
|
||||
* operationId: "PostPaymentCollectionsPaymentCollectionAuthorize"
|
||||
* summary: "Set the status of PaymentCollection as Authorized"
|
||||
* description: "Sets the status of PaymentCollection as Authorized."
|
||||
* x-authenticated: true
|
||||
|
||||
@@ -75,7 +75,7 @@ import { PaymentCollectionService } from "../../../../services"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const { id } = req.params
|
||||
const data = req.validatedBody as AdminUpdatePaymentCollectionRequest
|
||||
const data = req.validatedBody as AdminUpdatePaymentCollectionsReq
|
||||
|
||||
const paymentCollectionService: PaymentCollectionService = req.scope.resolve(
|
||||
"paymentCollectionService"
|
||||
@@ -93,7 +93,7 @@ export default async (req, res) => {
|
||||
res.status(200).json({ payment_collection: paymentCollection })
|
||||
}
|
||||
|
||||
export class AdminUpdatePaymentCollectionRequest {
|
||||
export class AdminUpdatePaymentCollectionsReq {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
description?: string
|
||||
|
||||
@@ -45,6 +45,11 @@ describe("GET /store/order-edits/:id/complete", () => {
|
||||
`/store/order-edits/${orderEditId}/complete`,
|
||||
{
|
||||
flags: [OrderEditingFeatureFlag],
|
||||
clientSession: {
|
||||
jwt: {
|
||||
user: IdMap.getId("lebron"),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
@@ -77,7 +77,7 @@ export default async (req: Request, res: Response) => {
|
||||
paymentProviderService.withTransaction(manager)
|
||||
|
||||
const orderEdit = await orderEditServiceTx.retrieve(id, {
|
||||
relations: ["payment_collection"],
|
||||
relations: ["payment_collection", "payment_collection.payments"],
|
||||
})
|
||||
|
||||
if (orderEdit.status === OrderEditStatus.CONFIRMED) {
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
import { IsArray, IsString } from "class-validator"
|
||||
import { PaymentCollectionService } from "../../../../services"
|
||||
|
||||
/**
|
||||
* @oas [post] /payment-collections/{id}/authorize
|
||||
* operationId: "PostPaymentCollectionsAuthorize"
|
||||
* summary: "Authorize a Payment Collections"
|
||||
* description: "Authorizes a Payment Collections."
|
||||
* x-authenticated: true
|
||||
* @oas [post] /payment-collections/{id}/sessions/batch/authorize
|
||||
* operationId: "PostPaymentCollectionsSessionsBatchAuthorize"
|
||||
* summary: "Authorize Payment Sessions of a Payment Collection"
|
||||
* description: "Authorizes Payment Sessions of a Payment Collection."
|
||||
* x-authenticated: false
|
||||
* parameters:
|
||||
* - (path) id=* {string} The ID of the Payment Collections.
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* session_ids:
|
||||
* description: "List of Payment Session IDs to authorize."
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* x-codeSamples:
|
||||
* - lang: JavaScript
|
||||
* label: JS Client
|
||||
@@ -22,8 +33,7 @@ import { PaymentCollectionService } from "../../../../services"
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request POST 'https://medusa-url.com/store/payment-collections/{id}/authorize' \
|
||||
* --header 'Authorization: Bearer {api_token}'
|
||||
* curl --location --request POST 'https://medusa-url.com/store/payment-collections/{id}/sessions/batch/authorize'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
@@ -35,7 +45,6 @@ import { PaymentCollectionService } from "../../../../services"
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* payment_collection:
|
||||
* $ref: "#/components/schemas/payment_collection"
|
||||
@@ -53,15 +62,26 @@ import { PaymentCollectionService } from "../../../../services"
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const { payment_id } = req.params
|
||||
const { id } = req.params
|
||||
const data =
|
||||
req.validatedBody as StorePostPaymentCollectionsBatchSessionsAuthorizeReq
|
||||
|
||||
const paymentCollectionService: PaymentCollectionService = req.scope.resolve(
|
||||
"paymentCollectionService"
|
||||
)
|
||||
|
||||
const payment_collection = await paymentCollectionService.authorize(
|
||||
payment_id
|
||||
)
|
||||
const payment_collection =
|
||||
await paymentCollectionService.authorizePaymentSessions(
|
||||
id,
|
||||
data.session_ids,
|
||||
req.request_context
|
||||
)
|
||||
|
||||
res.status(200).json({ payment_collection })
|
||||
res.status(207).json({ payment_collection })
|
||||
}
|
||||
|
||||
export class StorePostPaymentCollectionsBatchSessionsAuthorizeReq {
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
session_ids: string[]
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { PaymentSessionStatus } from "../../../../models"
|
||||
import { PaymentCollectionService } from "../../../../services"
|
||||
|
||||
/**
|
||||
* @oas [post] /payment-collections/{id}/sessions/{session_id}/authorize
|
||||
* operationId: "PostPaymentCollectionsSessionsSessionAuthorize"
|
||||
* summary: "Authorize a Payment Session of a Payment Collection"
|
||||
* description: "Authorizes a Payment Session of a Payment Collection."
|
||||
* x-authenticated: false
|
||||
* parameters:
|
||||
* - (path) id=* {string} The ID of the Payment Collections.
|
||||
* - (path) session_id=* {string} The ID of the Payment Session.
|
||||
* x-codeSamples:
|
||||
* - lang: JavaScript
|
||||
* label: JS Client
|
||||
* source: |
|
||||
* import Medusa from "@medusajs/medusa-js"
|
||||
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
|
||||
* // must be previously logged in or use api token
|
||||
* medusa.paymentCollections.authorize(payment_id, session_id)
|
||||
* .then(({ payment_collection }) => {
|
||||
* console.log(payment_collection.id);
|
||||
* });
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request POST 'https://medusa-url.com/store/payment-collections/{id}/sessions/{session_id}/authorize'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
* tags:
|
||||
* - Payment
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* payment_session:
|
||||
* $ref: "#/components/schemas/payment_session"
|
||||
* "400":
|
||||
* $ref: "#/components/responses/400_error"
|
||||
* "401":
|
||||
* $ref: "#/components/responses/unauthorized"
|
||||
* "404":
|
||||
* $ref: "#/components/responses/not_found_error"
|
||||
* "409":
|
||||
* $ref: "#/components/responses/invalid_state_error"
|
||||
* "422":
|
||||
* $ref: "#/components/responses/invalid_request_error"
|
||||
* "500":
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const { id, session_id } = req.params
|
||||
|
||||
const paymentCollectionService: PaymentCollectionService = req.scope.resolve(
|
||||
"paymentCollectionService"
|
||||
)
|
||||
|
||||
const payment_collection =
|
||||
await paymentCollectionService.authorizePaymentSessions(
|
||||
id,
|
||||
[session_id],
|
||||
req.request_context
|
||||
)
|
||||
|
||||
const session = payment_collection.payment_sessions.find(
|
||||
({ id }) => id === session_id
|
||||
)
|
||||
|
||||
if (session?.status !== PaymentSessionStatus.AUTHORIZED) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.PAYMENT_AUTHORIZATION_ERROR,
|
||||
`Failed to authorize Payment Session id "${id}"`
|
||||
)
|
||||
}
|
||||
|
||||
res.status(200).json({ payment_session: session })
|
||||
}
|
||||
@@ -3,10 +3,10 @@ import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [get] /payment-collections/{id}
|
||||
* operationId: "GetPaymentCollectonsPaymentCollection"
|
||||
* operationId: "GetPaymentCollectionsPaymentCollection"
|
||||
* summary: "Retrieve an PaymentCollection"
|
||||
* description: "Retrieves a PaymentCollection."
|
||||
* x-authenticated: true
|
||||
* x-authenticated: false
|
||||
* parameters:
|
||||
* - (path) id=* {string} The ID of the PaymentCollection.
|
||||
* - (query) expand {string} Comma separated list of relations to include in the results.
|
||||
@@ -25,8 +25,7 @@ import { FindParams } from "../../../../types/common"
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request GET 'https://medusa-url.com/store/payment-collections/{id}' \
|
||||
* --header 'Authorization: Bearer {api_token}'
|
||||
* curl --location --request GET 'https://medusa-url.com/store/payment-collections/{id}'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
|
||||
@@ -8,10 +8,11 @@ import middlewares, {
|
||||
import OrderEditingFeatureFlag from "../../../../loaders/feature-flags/order-editing"
|
||||
import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled"
|
||||
|
||||
import { StoreManagePaymentCollectionSessionRequest } from "./manage-payment-sessions"
|
||||
import { StoreRefreshPaymentCollectionSessionRequest } from "./refresh-payment-session"
|
||||
import { StorePostPaymentCollectionsBatchSessionsReq } from "./manage-batch-payment-sessions"
|
||||
import { GetPaymentCollectionsParams } from "./get-payment-collection"
|
||||
import { PaymentCollection, PaymentSession } from "../../../../models"
|
||||
import { StorePaymentCollectionSessionsReq } from "./manage-payment-session"
|
||||
import { StorePostPaymentCollectionsBatchSessionsAuthorizeReq } from "./authorize-batch-payment-sessions"
|
||||
|
||||
const route = Router()
|
||||
|
||||
@@ -33,22 +34,33 @@ export default (app, container) => {
|
||||
)
|
||||
|
||||
route.post(
|
||||
"/:id/authorize",
|
||||
middlewares.wrap(require("./authorize-payment-collection").default)
|
||||
"/:id/sessions/batch",
|
||||
transformBody(StorePostPaymentCollectionsBatchSessionsReq),
|
||||
middlewares.wrap(require("./manage-batch-payment-sessions").default)
|
||||
)
|
||||
|
||||
route.post(
|
||||
"/:id/sessions/batch/authorize",
|
||||
transformBody(StorePostPaymentCollectionsBatchSessionsAuthorizeReq),
|
||||
middlewares.wrap(require("./authorize-batch-payment-sessions").default)
|
||||
)
|
||||
|
||||
route.post(
|
||||
"/:id/sessions",
|
||||
transformBody(StoreManagePaymentCollectionSessionRequest),
|
||||
middlewares.wrap(require("./manage-payment-sessions").default)
|
||||
transformBody(StorePaymentCollectionSessionsReq),
|
||||
middlewares.wrap(require("./manage-payment-session").default)
|
||||
)
|
||||
|
||||
route.post(
|
||||
"/:id/sessions/:session_id/refresh",
|
||||
transformBody(StoreRefreshPaymentCollectionSessionRequest),
|
||||
"/:id/sessions/:session_id",
|
||||
middlewares.wrap(require("./refresh-payment-session").default)
|
||||
)
|
||||
|
||||
route.post(
|
||||
"/:id/sessions/:session_id/authorize",
|
||||
middlewares.wrap(require("./authorize-payment-session").default)
|
||||
)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
@@ -66,14 +78,16 @@ export const defaultPaymentCollectionFields = [
|
||||
|
||||
export const defaulPaymentCollectionRelations = ["region", "payment_sessions"]
|
||||
|
||||
export type StorePaymentCollectionRes = {
|
||||
export type StorePaymentCollectionsRes = {
|
||||
payment_collection: PaymentCollection
|
||||
}
|
||||
|
||||
export type StorePaymentCollectionSessionRes = {
|
||||
export type StorePaymentCollectionsSessionRes = {
|
||||
payment_session: PaymentSession
|
||||
}
|
||||
|
||||
export * from "./get-payment-collection"
|
||||
export * from "./manage-payment-sessions"
|
||||
export * from "./manage-payment-session"
|
||||
export * from "./manage-batch-payment-sessions"
|
||||
export * from "./refresh-payment-session"
|
||||
export * from "./authorize-batch-payment-sessions"
|
||||
|
||||
@@ -5,34 +5,29 @@ import { EntityManager } from "typeorm"
|
||||
import { PaymentCollectionService } from "../../../../services"
|
||||
|
||||
/**
|
||||
* @oas [post] /payment-collections/{id}/sessions
|
||||
* operationId: "PostPaymentCollectionsSessions"
|
||||
* summary: "Manage Payment Sessions from Payment Collections"
|
||||
* description: "Manages Payment Sessions from Payment Collections."
|
||||
* x-authenticated: true
|
||||
* @oas [post] /payment-collections/{id}/sessions/batch
|
||||
* operationId: "PostPaymentCollectionsPaymentCollectionSessionsBatch"
|
||||
* summary: "Manage Multiple Payment Sessions from Payment Collections"
|
||||
* description: "Manages Multiple Payment Sessions from Payment Collections."
|
||||
* x-authenticated: false
|
||||
* parameters:
|
||||
* - (path) id=* {string} The ID of the Payment Collections.
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* sessions:
|
||||
* description: "An array or a single entry of payment sessions related to the Payment Collection. If the session_id is not provided the existing sessions not present will be deleted and the provided ones will be created."
|
||||
* description: "An array of payment sessions related to the Payment Collection. If the session_id is not provided, existing sessions not present will be deleted and the provided ones will be created."
|
||||
* type: array
|
||||
* items:
|
||||
* required:
|
||||
* - provider_id
|
||||
* - customer_id
|
||||
* - amount
|
||||
* properties:
|
||||
* provider_id:
|
||||
* type: string
|
||||
* description: The ID of the Payment Provider.
|
||||
* customer_id:
|
||||
* type: string
|
||||
* description: "The ID of the Customer."
|
||||
* amount:
|
||||
* type: integer
|
||||
* description: "The amount ."
|
||||
@@ -50,15 +45,13 @@ import { PaymentCollectionService } from "../../../../services"
|
||||
* // Total amount = 10000
|
||||
*
|
||||
* // Adding two new sessions
|
||||
* medusa.paymentCollections.manageSessions(payment_id, [
|
||||
* medusa.paymentCollections.managePaymentSessionsBatch(payment_id, [
|
||||
* {
|
||||
* provider_id: "stripe",
|
||||
* customer_id: "cus_123",
|
||||
* amount: 5000,
|
||||
* },
|
||||
* {
|
||||
* provider_id: "manual",
|
||||
* customer_id: "cus_123",
|
||||
* amount: 5000,
|
||||
* },
|
||||
* ])
|
||||
@@ -67,20 +60,20 @@ import { PaymentCollectionService } from "../../../../services"
|
||||
* });
|
||||
*
|
||||
* // Updating one session and removing the other
|
||||
* medusa.paymentCollections.manageSessions(payment_id, {
|
||||
* medusa.paymentCollections.managePaymentSessionsBatch(payment_id, [
|
||||
* {
|
||||
* provider_id: "stripe",
|
||||
* customer_id: "cus_123",
|
||||
* amount: 10000,
|
||||
* session_id: "ps_123456"
|
||||
* })
|
||||
* },
|
||||
* ])
|
||||
* .then(({ payment_collection }) => {
|
||||
* console.log(payment_collection.id);
|
||||
* });
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request POST 'https://medusa-url.com/store/payment-collections/{id}/sessions' \
|
||||
* --header 'Authorization: Bearer {api_token}'
|
||||
* curl --location --request POST 'https://medusa-url.com/store/payment-collections/{id}/sessions/batch'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
@@ -92,7 +85,6 @@ import { PaymentCollectionService } from "../../../../services"
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* payment_collection:
|
||||
* $ref: "#/components/schemas/payment_collection"
|
||||
@@ -110,9 +102,11 @@ import { PaymentCollectionService } from "../../../../services"
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const data = req.validatedBody as StoreManagePaymentCollectionSessionRequest
|
||||
const data = req.validatedBody as StorePostPaymentCollectionsBatchSessionsReq
|
||||
const { id } = req.params
|
||||
|
||||
const customerId = req.user?.customer_id
|
||||
|
||||
const paymentCollectionService: PaymentCollectionService = req.scope.resolve(
|
||||
"paymentCollectionService"
|
||||
)
|
||||
@@ -122,20 +116,17 @@ export default async (req, res) => {
|
||||
async (transactionManager) => {
|
||||
return await paymentCollectionService
|
||||
.withTransaction(transactionManager)
|
||||
.setPaymentSessions(id, data.sessions)
|
||||
.setPaymentSessionsBatch(id, data.sessions, customerId)
|
||||
}
|
||||
)
|
||||
|
||||
res.status(200).json({ payment_collection: paymentCollection })
|
||||
}
|
||||
|
||||
export class PaymentCollectionSessionInputRequest {
|
||||
export class StorePostPaymentCollectionsSessionsReq {
|
||||
@IsString()
|
||||
provider_id: string
|
||||
|
||||
@IsString()
|
||||
customer_id: string
|
||||
|
||||
@IsInt()
|
||||
@IsNotEmpty()
|
||||
amount: number
|
||||
@@ -145,12 +136,7 @@ export class PaymentCollectionSessionInputRequest {
|
||||
session_id?: string
|
||||
}
|
||||
|
||||
export class StoreManagePaymentCollectionSessionRequest {
|
||||
@IsType([
|
||||
PaymentCollectionSessionInputRequest,
|
||||
[PaymentCollectionSessionInputRequest],
|
||||
])
|
||||
sessions:
|
||||
| PaymentCollectionSessionInputRequest
|
||||
| PaymentCollectionSessionInputRequest[]
|
||||
export class StorePostPaymentCollectionsBatchSessionsReq {
|
||||
@IsType([[StorePostPaymentCollectionsSessionsReq]])
|
||||
sessions: StorePostPaymentCollectionsSessionsReq[]
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import { IsString } from "class-validator"
|
||||
|
||||
import { EntityManager } from "typeorm"
|
||||
import { PaymentCollectionService } from "../../../../services"
|
||||
|
||||
/**
|
||||
* @oas [post] /payment-collections/{id}/sessions
|
||||
* operationId: "PostPaymentCollectionsSessions"
|
||||
* summary: "Manage Payment Sessions from Payment Collections"
|
||||
* description: "Manages Payment Sessions from Payment Collections."
|
||||
* x-authenticated: false
|
||||
* parameters:
|
||||
* - (path) id=* {string} The ID of the Payment Collection.
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* required:
|
||||
* - provider_id
|
||||
* properties:
|
||||
* provider_id:
|
||||
* type: string
|
||||
* description: The ID of the Payment Provider.
|
||||
* x-codeSamples:
|
||||
* - lang: JavaScript
|
||||
* label: JS Client
|
||||
* source: |
|
||||
* import Medusa from "@medusajs/medusa-js"
|
||||
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
|
||||
* // must be previously logged in or use api token
|
||||
*
|
||||
* // Total amount = 10000
|
||||
*
|
||||
* // Adding a payment session
|
||||
* medusa.paymentCollections.managePaymentSession(payment_id, { provider_id: "stripe" })
|
||||
* .then(({ payment_collection }) => {
|
||||
* console.log(payment_collection.id);
|
||||
* });
|
||||
*
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request POST 'https://medusa-url.com/store/payment-collections/{id}/sessions'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
* tags:
|
||||
* - Payment
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* payment_collection:
|
||||
* $ref: "#/components/schemas/payment_collection"
|
||||
* "400":
|
||||
* $ref: "#/components/responses/400_error"
|
||||
* "401":
|
||||
* $ref: "#/components/responses/unauthorized"
|
||||
* "404":
|
||||
* $ref: "#/components/responses/not_found_error"
|
||||
* "409":
|
||||
* $ref: "#/components/responses/invalid_state_error"
|
||||
* "422":
|
||||
* $ref: "#/components/responses/invalid_request_error"
|
||||
* "500":
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const data = req.validatedBody as StorePaymentCollectionSessionsReq
|
||||
const { id } = req.params
|
||||
|
||||
const customerId = req.user?.customer_id
|
||||
|
||||
const paymentCollectionService: PaymentCollectionService = req.scope.resolve(
|
||||
"paymentCollectionService"
|
||||
)
|
||||
|
||||
const manager: EntityManager = req.scope.resolve("manager")
|
||||
|
||||
const paymentCollection = await manager.transaction(
|
||||
async (transactionManager) => {
|
||||
return await paymentCollectionService
|
||||
.withTransaction(transactionManager)
|
||||
.setPaymentSession(id, data, customerId)
|
||||
}
|
||||
)
|
||||
|
||||
res.status(200).json({ payment_collection: paymentCollection })
|
||||
}
|
||||
|
||||
export class StorePaymentCollectionSessionsReq {
|
||||
@IsString()
|
||||
provider_id: string
|
||||
}
|
||||
@@ -4,10 +4,11 @@ import { EntityManager } from "typeorm"
|
||||
import { PaymentCollectionService } from "../../../../services"
|
||||
|
||||
/**
|
||||
* @oas [post] /payment-collections/{id}/sessions/{session_id}/refresh
|
||||
* @oas [post] /payment-collections/{id}/sessions/{session_id}
|
||||
* operationId: PostPaymentCollectionsPaymentCollectionPaymentSessionsSession
|
||||
* summary: Refresh a Payment Session
|
||||
* description: "Refreshes a Payment Session to ensure that it is in sync with the Payment Collection."
|
||||
* x-authenticated: false
|
||||
* parameters:
|
||||
* - (path) id=* {string} The id of the PaymentCollection.
|
||||
* - (path) session_id=* {string} The id of the Payment Session to be refreshed.
|
||||
@@ -33,13 +34,13 @@ import { PaymentCollectionService } from "../../../../services"
|
||||
* import Medusa from "@medusajs/medusa-js"
|
||||
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
|
||||
* medusa.paymentCollections.refreshPaymentSession(payment_collection_id, session_id, payload)
|
||||
* .then(({ payment_collection }) => {
|
||||
* console.log(payment_collection.id);
|
||||
* .then(({ payment_session }) => {
|
||||
* console.log(payment_session.id);
|
||||
* });
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request POST 'https://medusa-url.com/store/payment-collections/{id}/sessions/{session_id}/refresh'
|
||||
* curl --location --request POST 'https://medusa-url.com/store/payment-collections/{id}/sessions/{session_id}'
|
||||
* tags:
|
||||
* - PaymentCollection
|
||||
* responses:
|
||||
@@ -64,29 +65,22 @@ import { PaymentCollectionService } from "../../../../services"
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const data = req.validatedBody as StoreRefreshPaymentCollectionSessionRequest
|
||||
const { id, session_id } = req.params
|
||||
|
||||
const paymentCollectionService: PaymentCollectionService = req.scope.resolve(
|
||||
"paymentCollectionService"
|
||||
)
|
||||
|
||||
const customerId = req.user?.customer_id
|
||||
|
||||
const manager: EntityManager = req.scope.resolve("manager")
|
||||
const paymentSession = await manager.transaction(
|
||||
async (transactionManager) => {
|
||||
return await paymentCollectionService
|
||||
.withTransaction(transactionManager)
|
||||
.refreshPaymentSession(id, session_id, data)
|
||||
.refreshPaymentSession(id, session_id, customerId)
|
||||
}
|
||||
)
|
||||
|
||||
res.status(200).json({ payment_session: paymentSession })
|
||||
}
|
||||
|
||||
export class StoreRefreshPaymentCollectionSessionRequest {
|
||||
@IsString()
|
||||
provider_id: string
|
||||
|
||||
@IsString()
|
||||
customer_id: string
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ export const CustomerServiceMock = {
|
||||
password_hash: "1234",
|
||||
})
|
||||
}
|
||||
return Promise.resolve()
|
||||
}),
|
||||
retrieveByEmail: jest.fn().mockImplementation((email) => {
|
||||
if (email === "lebron@james.com") {
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
PaymentProviderServiceMock,
|
||||
} from "../__mocks__/payment-provider"
|
||||
import { CustomerServiceMock } from "../__mocks__/customer"
|
||||
import { PaymentCollectionSessionInput } from "../../types/payment-collection"
|
||||
import { PaymentCollectionsSessionsBatchInput } from "../../types/payment-collection"
|
||||
|
||||
describe("PaymentCollectionService", () => {
|
||||
afterEach(() => {
|
||||
@@ -376,20 +376,18 @@ describe("PaymentCollectionService", () => {
|
||||
expect(entity).rejects.toThrow(Error)
|
||||
})
|
||||
|
||||
describe("Manage Payment Sessions", () => {
|
||||
describe("Manage Single Payment Session", () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("should throw error if payment collection doesn't have the correct status", async () => {
|
||||
const inp: PaymentCollectionSessionInput = {
|
||||
amount: 100,
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
customer_id: "customer1",
|
||||
}
|
||||
const ret = paymentCollectionService.setPaymentSessions(
|
||||
const ret = paymentCollectionService.setPaymentSession(
|
||||
IdMap.getId("payment-collection-id2"),
|
||||
inp
|
||||
{
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
},
|
||||
"customer1"
|
||||
)
|
||||
|
||||
expect(ret).rejects.toThrowError(
|
||||
@@ -400,15 +398,120 @@ describe("PaymentCollectionService", () => {
|
||||
expect(PaymentProviderServiceMock.createSessionNew).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it("should throw error if amount is different than requested", async () => {
|
||||
const inp: PaymentCollectionSessionInput = {
|
||||
amount: 101,
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
customer_id: "customer1",
|
||||
}
|
||||
const ret = paymentCollectionService.setPaymentSessions(
|
||||
it("should ignore session if provider doesn't belong to the region", async () => {
|
||||
const multiRet = paymentCollectionService.setPaymentSession(
|
||||
IdMap.getId("payment-collection-id1"),
|
||||
inp
|
||||
{
|
||||
provider_id: IdMap.getId("region1_invalid_provider"),
|
||||
},
|
||||
"customer1"
|
||||
)
|
||||
|
||||
expect(multiRet).rejects.toThrow(`Payment provider not found`)
|
||||
expect(PaymentProviderServiceMock.createSessionNew).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it("should add a new session", async () => {
|
||||
await paymentCollectionService.setPaymentSession(
|
||||
IdMap.getId("payment-collection-id1"),
|
||||
{
|
||||
provider_id: IdMap.getId("region1_provider2"),
|
||||
},
|
||||
"lebron"
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes(
|
||||
1
|
||||
)
|
||||
expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1)
|
||||
expect(paymentCollectionRepository.save).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("should update an existing one", async () => {
|
||||
await paymentCollectionService.setPaymentSession(
|
||||
IdMap.getId("payment-collection-id1"),
|
||||
{
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
},
|
||||
"lebron"
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes(
|
||||
0
|
||||
)
|
||||
expect(PaymentProviderServiceMock.updateSessionNew).toHaveBeenCalledTimes(
|
||||
1
|
||||
)
|
||||
expect(CustomerServiceMock.retrieve).toHaveBeenCalledTimes(1)
|
||||
expect(paymentCollectionRepository.save).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("should add a new session and delete existing one", async () => {
|
||||
const inp: PaymentCollectionsSessionsBatchInput[] = [
|
||||
{
|
||||
amount: 100,
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
},
|
||||
]
|
||||
await paymentCollectionService.setPaymentSessionsBatch(
|
||||
IdMap.getId("payment-collection-session"),
|
||||
inp,
|
||||
IdMap.getId("lebron")
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes(
|
||||
1
|
||||
)
|
||||
expect(PaymentProviderServiceMock.updateSessionNew).toHaveBeenCalledTimes(
|
||||
0
|
||||
)
|
||||
expect(paymentCollectionRepository.deleteMultiple).toHaveBeenCalledTimes(
|
||||
1
|
||||
)
|
||||
|
||||
expect(paymentCollectionRepository.save).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe("Manage Multiple Payment Sessions", () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("should throw error if payment collection doesn't have the correct status", async () => {
|
||||
const inp: PaymentCollectionsSessionsBatchInput[] = [
|
||||
{
|
||||
amount: 100,
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
},
|
||||
]
|
||||
const ret = paymentCollectionService.setPaymentSessionsBatch(
|
||||
IdMap.getId("payment-collection-id2"),
|
||||
inp,
|
||||
"customer1"
|
||||
)
|
||||
|
||||
expect(ret).rejects.toThrowError(
|
||||
new Error(
|
||||
`Cannot set payment sessions for a payment collection with status ${PaymentCollectionStatus.AUTHORIZED}`
|
||||
)
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.createSessionNew).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it("should throw error if amount is different than requested", async () => {
|
||||
const inp: PaymentCollectionsSessionsBatchInput[] = [
|
||||
{
|
||||
amount: 101,
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
},
|
||||
]
|
||||
|
||||
const ret = paymentCollectionService.setPaymentSessionsBatch(
|
||||
IdMap.getId("payment-collection-id1"),
|
||||
inp,
|
||||
"customer1"
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes(
|
||||
@@ -418,21 +521,20 @@ describe("PaymentCollectionService", () => {
|
||||
`The sum of sessions is not equal to 100 on Payment Collection`
|
||||
)
|
||||
|
||||
const multInp: PaymentCollectionSessionInput[] = [
|
||||
const multInp: PaymentCollectionsSessionsBatchInput[] = [
|
||||
{
|
||||
amount: 51,
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
customer_id: "customer1",
|
||||
},
|
||||
{
|
||||
amount: 50,
|
||||
provider_id: IdMap.getId("region1_provider2"),
|
||||
customer_id: "customer1",
|
||||
},
|
||||
]
|
||||
const multiRet = paymentCollectionService.setPaymentSessions(
|
||||
const multiRet = paymentCollectionService.setPaymentSessionsBatch(
|
||||
IdMap.getId("payment-collection-id1"),
|
||||
multInp
|
||||
multInp,
|
||||
"customer1"
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes(
|
||||
@@ -444,21 +546,20 @@ describe("PaymentCollectionService", () => {
|
||||
})
|
||||
|
||||
it("should ignore sessions where provider doesn't belong to the region", async () => {
|
||||
const multInp: PaymentCollectionSessionInput[] = [
|
||||
const multInp: PaymentCollectionsSessionsBatchInput[] = [
|
||||
{
|
||||
amount: 50,
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
customer_id: "customer1",
|
||||
},
|
||||
{
|
||||
amount: 50,
|
||||
provider_id: IdMap.getId("region1_invalid_provider"),
|
||||
customer_id: "customer1",
|
||||
},
|
||||
]
|
||||
const multiRet = paymentCollectionService.setPaymentSessions(
|
||||
const multiRet = paymentCollectionService.setPaymentSessionsBatch(
|
||||
IdMap.getId("payment-collection-id1"),
|
||||
multInp
|
||||
multInp,
|
||||
"customer1"
|
||||
)
|
||||
|
||||
expect(multiRet).rejects.toThrow(
|
||||
@@ -468,22 +569,21 @@ describe("PaymentCollectionService", () => {
|
||||
})
|
||||
|
||||
it("should add a new session and update existing one", async () => {
|
||||
const inp: PaymentCollectionSessionInput[] = [
|
||||
const inp: PaymentCollectionsSessionsBatchInput[] = [
|
||||
{
|
||||
session_id: IdMap.getId("payCol_session1"),
|
||||
amount: 50,
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
customer_id: IdMap.getId("lebron"),
|
||||
},
|
||||
{
|
||||
amount: 50,
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
customer_id: IdMap.getId("lebron"),
|
||||
},
|
||||
]
|
||||
await paymentCollectionService.setPaymentSessions(
|
||||
await paymentCollectionService.setPaymentSessionsBatch(
|
||||
IdMap.getId("payment-collection-session"),
|
||||
inp
|
||||
inp,
|
||||
"lebron"
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes(
|
||||
@@ -497,16 +597,16 @@ describe("PaymentCollectionService", () => {
|
||||
})
|
||||
|
||||
it("should add a new session and delete existing one", async () => {
|
||||
const inp: PaymentCollectionSessionInput[] = [
|
||||
const inp: PaymentCollectionsSessionsBatchInput[] = [
|
||||
{
|
||||
amount: 100,
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
customer_id: IdMap.getId("lebron"),
|
||||
},
|
||||
]
|
||||
await paymentCollectionService.setPaymentSessions(
|
||||
await paymentCollectionService.setPaymentSessionsBatch(
|
||||
IdMap.getId("payment-collection-session"),
|
||||
inp
|
||||
inp,
|
||||
IdMap.getId("lebron")
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.createSessionNew).toHaveBeenCalledTimes(
|
||||
@@ -526,10 +626,7 @@ describe("PaymentCollectionService", () => {
|
||||
await paymentCollectionService.refreshPaymentSession(
|
||||
IdMap.getId("payment-collection-session"),
|
||||
IdMap.getId("payCol_session1"),
|
||||
{
|
||||
customer_id: "customer1",
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
}
|
||||
"customer1"
|
||||
)
|
||||
|
||||
expect(
|
||||
@@ -545,10 +642,7 @@ describe("PaymentCollectionService", () => {
|
||||
const sess = paymentCollectionService.refreshPaymentSession(
|
||||
IdMap.getId("payment-collection-session"),
|
||||
IdMap.getId("payCol_session-not-found"),
|
||||
{
|
||||
customer_id: "customer1",
|
||||
provider_id: IdMap.getId("region1_provider1"),
|
||||
}
|
||||
"customer1"
|
||||
)
|
||||
|
||||
expect(sess).rejects.toThrow(
|
||||
@@ -567,19 +661,22 @@ describe("PaymentCollectionService", () => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it("should mark as paid if amount is 0", async () => {
|
||||
await paymentCollectionService.authorize(
|
||||
IdMap.getId("payment-collection-zero")
|
||||
it("should mark as authorized if amount is 0", async () => {
|
||||
const auth = await paymentCollectionService.authorizePaymentSessions(
|
||||
IdMap.getId("payment-collection-zero"),
|
||||
[]
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.authorizePayment).toHaveBeenCalledTimes(
|
||||
0
|
||||
)
|
||||
expect(auth.status).toBe(PaymentCollectionStatus.AUTHORIZED)
|
||||
})
|
||||
|
||||
it("should reject payment collection without payment sessions", async () => {
|
||||
const ret = paymentCollectionService.authorize(
|
||||
IdMap.getId("payment-collection-no-session")
|
||||
const ret = paymentCollectionService.authorizePaymentSessions(
|
||||
IdMap.getId("payment-collection-no-session"),
|
||||
[]
|
||||
)
|
||||
|
||||
expect(ret).rejects.toThrowError(
|
||||
@@ -590,8 +687,9 @@ describe("PaymentCollectionService", () => {
|
||||
})
|
||||
|
||||
it("should call authorizePayments for all sessions", async () => {
|
||||
await paymentCollectionService.authorize(
|
||||
IdMap.getId("payment-collection-not-authorized")
|
||||
await paymentCollectionService.authorizePaymentSessions(
|
||||
IdMap.getId("payment-collection-not-authorized"),
|
||||
[IdMap.getId("payCol_session1"), IdMap.getId("payCol_session2")]
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.authorizePayment).toHaveBeenCalledTimes(
|
||||
@@ -604,8 +702,9 @@ describe("PaymentCollectionService", () => {
|
||||
})
|
||||
|
||||
it("should skip authorized sessions - partially authorized", async () => {
|
||||
await paymentCollectionService.authorize(
|
||||
IdMap.getId("payment-collection-partial")
|
||||
await paymentCollectionService.authorizePaymentSessions(
|
||||
IdMap.getId("payment-collection-partial"),
|
||||
[IdMap.getId("payCol_session1"), IdMap.getId("payCol_session2")]
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.authorizePayment).toHaveBeenCalledTimes(
|
||||
@@ -618,8 +717,9 @@ describe("PaymentCollectionService", () => {
|
||||
})
|
||||
|
||||
it("should skip authorized sessions - fully authorized", async () => {
|
||||
await paymentCollectionService.authorize(
|
||||
IdMap.getId("payment-collection-fully")
|
||||
await paymentCollectionService.authorizePaymentSessions(
|
||||
IdMap.getId("payment-collection-fully"),
|
||||
[IdMap.getId("payCol_session1"), IdMap.getId("payCol_session2")]
|
||||
)
|
||||
|
||||
expect(PaymentProviderServiceMock.authorizePayment).toHaveBeenCalledTimes(
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { DeepPartial, EntityManager, Equal } from "typeorm"
|
||||
import { DeepPartial, EntityManager } from "typeorm"
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
|
||||
import { FindConfig } from "../types/common"
|
||||
import { buildQuery, isDefined, setMetadata } from "../utils"
|
||||
import { PaymentCollectionRepository } from "../repositories/payment-collection"
|
||||
import {
|
||||
Customer,
|
||||
PaymentCollection,
|
||||
PaymentCollectionStatus,
|
||||
PaymentSession,
|
||||
@@ -16,12 +15,12 @@ import {
|
||||
CustomerService,
|
||||
EventBusService,
|
||||
PaymentProviderService,
|
||||
PaymentService,
|
||||
} from "./index"
|
||||
|
||||
import {
|
||||
CreatePaymentCollectionInput,
|
||||
PaymentCollectionSessionInput,
|
||||
PaymentCollectionsSessionsBatchInput,
|
||||
PaymentCollectionsSessionsInput,
|
||||
PaymentProviderDataInput,
|
||||
} from "../types/payment-collection"
|
||||
|
||||
@@ -66,6 +65,12 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
this.customerService_ = customerService
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a payment collection by id.
|
||||
* @param paymentCollectionId - the id of the payment collection
|
||||
* @param config - the config to retrieve the payment collection
|
||||
* @return the payment collection.
|
||||
*/
|
||||
async retrieve(
|
||||
paymentCollectionId: string,
|
||||
config: FindConfig<PaymentCollection> = {}
|
||||
@@ -75,9 +80,11 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
this.paymentCollectionRepository_
|
||||
)
|
||||
|
||||
const query = buildQuery({ id: paymentCollectionId }, config)
|
||||
|
||||
const paymentCollection = await paymentCollectionRepository.find(query)
|
||||
let paymentCollection: PaymentCollection[] = []
|
||||
if (paymentCollectionId) {
|
||||
const query = buildQuery({ id: paymentCollectionId }, config)
|
||||
paymentCollection = await paymentCollectionRepository.find(query)
|
||||
}
|
||||
|
||||
if (!paymentCollection.length) {
|
||||
throw new MedusaError(
|
||||
@@ -89,6 +96,11 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
return paymentCollection[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new payment collection.
|
||||
* @param data - info to create the payment collection
|
||||
* @return the payment collection created.
|
||||
*/
|
||||
async create(data: CreatePaymentCollectionInput): Promise<PaymentCollection> {
|
||||
return await this.atomicPhase_(async (manager) => {
|
||||
const paymentCollectionRepository = manager.getCustomRepository(
|
||||
@@ -118,6 +130,12 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a payment collection.
|
||||
* @param paymentCollectionId - the id of the payment collection to update
|
||||
* @param data - info to be updated
|
||||
* @return the payment collection updated.
|
||||
*/
|
||||
async update(
|
||||
paymentCollectionId: string,
|
||||
data: DeepPartial<PaymentCollection>
|
||||
@@ -147,6 +165,11 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a payment collection.
|
||||
* @param paymentCollectionId - the id of the payment collection to be removed
|
||||
* @return the payment collection removed.
|
||||
*/
|
||||
async delete(
|
||||
paymentCollectionId: string
|
||||
): Promise<PaymentCollection | undefined> {
|
||||
@@ -187,18 +210,24 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
|
||||
private isValidTotalAmount(
|
||||
total: number,
|
||||
sessionsInput: PaymentCollectionSessionInput[]
|
||||
sessionsInput: PaymentCollectionsSessionsBatchInput[]
|
||||
): boolean {
|
||||
const sum = sessionsInput.reduce((cur, sess) => cur + sess.amount, 0)
|
||||
return total === sum
|
||||
}
|
||||
|
||||
async setPaymentSessions(
|
||||
/**
|
||||
* Manages multiple payment sessions of a payment collection.
|
||||
* @param paymentCollectionId - the id of the payment collection
|
||||
* @param sessionsInput - array containing payment session info
|
||||
* @param customerId - the id of the customer
|
||||
* @return the payment collection and its payment sessions.
|
||||
*/
|
||||
async setPaymentSessionsBatch(
|
||||
paymentCollectionId: string,
|
||||
sessions: PaymentCollectionSessionInput[] | PaymentCollectionSessionInput
|
||||
sessionsInput: PaymentCollectionsSessionsBatchInput[],
|
||||
customerId: string
|
||||
): Promise<PaymentCollection> {
|
||||
let sessionsInput = Array.isArray(sessions) ? sessions : [sessions]
|
||||
|
||||
return await this.atomicPhase_(async (manager: EntityManager) => {
|
||||
const paymentCollectionRepository = manager.getCustomRepository(
|
||||
this.paymentCollectionRepository_
|
||||
@@ -228,20 +257,19 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
)
|
||||
}
|
||||
|
||||
let customer: Customer | undefined = undefined
|
||||
const customer = !isDefined(customerId)
|
||||
? null
|
||||
: await this.customerService_
|
||||
.withTransaction(manager)
|
||||
.retrieve(customerId, {
|
||||
select: ["id", "email", "metadata"],
|
||||
})
|
||||
.catch(() => null)
|
||||
|
||||
const selectedSessionIds: string[] = []
|
||||
const paymentSessions: PaymentSession[] = []
|
||||
|
||||
for (const session of sessionsInput) {
|
||||
if (!customer) {
|
||||
customer = await this.customerService_
|
||||
.withTransaction(manager)
|
||||
.retrieve(session.customer_id, {
|
||||
select: ["id", "email", "metadata"],
|
||||
})
|
||||
}
|
||||
|
||||
const existingSession = payCol.payment_sessions?.find(
|
||||
(sess) => session.session_id === sess?.id
|
||||
)
|
||||
@@ -252,9 +280,6 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
amount: session.amount,
|
||||
provider_id: session.provider_id,
|
||||
customer,
|
||||
metadata: {
|
||||
resource_id: payCol.id,
|
||||
},
|
||||
}
|
||||
|
||||
if (existingSession) {
|
||||
@@ -275,12 +300,22 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
}
|
||||
|
||||
if (payCol.payment_sessions?.length) {
|
||||
const removeIds: string[] = payCol.payment_sessions
|
||||
.map((sess) => sess.id)
|
||||
.filter((id) => !selectedSessionIds.includes(id))
|
||||
const removeSessions: PaymentSession[] = payCol.payment_sessions.filter(
|
||||
({ id }) => !selectedSessionIds.includes(id)
|
||||
)
|
||||
|
||||
if (removeIds.length) {
|
||||
await paymentCollectionRepository.deleteMultiple(removeIds)
|
||||
if (removeSessions.length) {
|
||||
await paymentCollectionRepository.deleteMultiple(
|
||||
removeSessions.map((sess) => sess.id)
|
||||
)
|
||||
|
||||
Promise.all(
|
||||
removeSessions.map(async (sess) =>
|
||||
this.paymentProviderService_
|
||||
.withTransaction(manager)
|
||||
.deleteSessionNew(sess)
|
||||
)
|
||||
).catch(() => void 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,10 +325,116 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages a single payment sessions of a payment collection.
|
||||
* @param paymentCollectionId - the id of the payment collection
|
||||
* @param sessionsInput - object containing payment session info
|
||||
* @param customerId - the id of the customer
|
||||
* @return the payment collection and its payment session.
|
||||
*/
|
||||
async setPaymentSession(
|
||||
paymentCollectionId: string,
|
||||
sessionInput: PaymentCollectionsSessionsInput,
|
||||
customerId: string
|
||||
): Promise<PaymentCollection> {
|
||||
return await this.atomicPhase_(async (manager: EntityManager) => {
|
||||
const paymentCollectionRepository = manager.getCustomRepository(
|
||||
this.paymentCollectionRepository_
|
||||
)
|
||||
|
||||
const payCol = await this.retrieve(paymentCollectionId, {
|
||||
relations: ["region", "region.payment_providers", "payment_sessions"],
|
||||
})
|
||||
|
||||
if (payCol.status !== PaymentCollectionStatus.NOT_PAID) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
`Cannot set payment sessions for a payment collection with status ${payCol.status}`
|
||||
)
|
||||
}
|
||||
|
||||
const hasProvider = payCol?.region?.payment_providers
|
||||
.map((p) => p.id)
|
||||
.includes(sessionInput.provider_id)
|
||||
|
||||
if (!hasProvider) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Payment provider not found"
|
||||
)
|
||||
}
|
||||
|
||||
const customer = !isDefined(customerId)
|
||||
? null
|
||||
: await this.customerService_
|
||||
.withTransaction(manager)
|
||||
.retrieve(customerId, {
|
||||
select: ["id", "email", "metadata"],
|
||||
})
|
||||
.catch(() => null)
|
||||
|
||||
const paymentSessions: PaymentSession[] = []
|
||||
const inputData: PaymentProviderDataInput = {
|
||||
resource_id: payCol.id,
|
||||
currency_code: payCol.currency_code,
|
||||
amount: payCol.amount,
|
||||
provider_id: sessionInput.provider_id,
|
||||
customer,
|
||||
}
|
||||
|
||||
const existingSession = payCol.payment_sessions?.find(
|
||||
(sess) => sessionInput.provider_id === sess?.provider_id
|
||||
)
|
||||
|
||||
if (existingSession) {
|
||||
const paymentSession = await this.paymentProviderService_
|
||||
.withTransaction(manager)
|
||||
.updateSessionNew(existingSession, inputData)
|
||||
|
||||
paymentSessions.push(paymentSession)
|
||||
} else {
|
||||
const paymentSession = await this.paymentProviderService_
|
||||
.withTransaction(manager)
|
||||
.createSessionNew(inputData)
|
||||
|
||||
paymentSessions.push(paymentSession)
|
||||
|
||||
const removeSessions: PaymentSession[] = payCol.payment_sessions.filter(
|
||||
({ id }) => id != paymentSession.id
|
||||
)
|
||||
|
||||
if (removeSessions.length) {
|
||||
await paymentCollectionRepository.deleteMultiple(
|
||||
removeSessions.map((sess) => sess.id)
|
||||
)
|
||||
|
||||
Promise.all(
|
||||
removeSessions.map(async (sess) =>
|
||||
this.paymentProviderService_
|
||||
.withTransaction(manager)
|
||||
.deleteSessionNew(sess)
|
||||
)
|
||||
).catch(() => void 0)
|
||||
}
|
||||
}
|
||||
|
||||
payCol.payment_sessions = paymentSessions
|
||||
|
||||
return await paymentCollectionRepository.save(payCol)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and recreate a payment session of a payment collection.
|
||||
* @param paymentCollectionId - the id of the payment collection
|
||||
* @param sessionId - the id of the payment session to be replaced
|
||||
* @param customerId - the id of the customer
|
||||
* @return the new payment session created.
|
||||
*/
|
||||
async refreshPaymentSession(
|
||||
paymentCollectionId: string,
|
||||
sessionId: string,
|
||||
sessionInput: Omit<PaymentCollectionSessionInput, "amount">
|
||||
customerId: string
|
||||
): Promise<PaymentSession> {
|
||||
return await this.atomicPhase_(async (manager: EntityManager) => {
|
||||
const paymentCollectionRepository = manager.getCustomRepository(
|
||||
@@ -330,11 +471,14 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
)
|
||||
}
|
||||
|
||||
const customer = await this.customerService_
|
||||
.withTransaction(manager)
|
||||
.retrieve(sessionInput.customer_id, {
|
||||
select: ["id", "email", "metadata"],
|
||||
})
|
||||
const customer = !isDefined(customerId)
|
||||
? null
|
||||
: await this.customerService_
|
||||
.withTransaction(manager)
|
||||
.retrieve(customerId, {
|
||||
select: ["id", "email", "metadata"],
|
||||
})
|
||||
.catch(() => null)
|
||||
|
||||
const inputData: PaymentProviderDataInput = {
|
||||
resource_id: payCol.id,
|
||||
@@ -365,6 +509,11 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a payment collection as authorized bypassing the payment flow.
|
||||
* @param paymentCollectionId - the id of the payment collection
|
||||
* @return the payment session authorized.
|
||||
*/
|
||||
async markAsAuthorized(
|
||||
paymentCollectionId: string
|
||||
): Promise<PaymentCollection> {
|
||||
@@ -387,8 +536,16 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
})
|
||||
}
|
||||
|
||||
async authorize(
|
||||
/**
|
||||
* Authorizes the payment sessions of a payment collection.
|
||||
* @param paymentCollectionId - the id of the payment collection
|
||||
* @param sessionIds - array of payment session ids to be authorized
|
||||
* @param context - additional data required by payment providers
|
||||
* @return the payment collection and its payment session.
|
||||
*/
|
||||
async authorizePaymentSessions(
|
||||
paymentCollectionId: string,
|
||||
sessionIds: string[],
|
||||
context: Record<string, unknown> = {}
|
||||
): Promise<PaymentCollection> {
|
||||
return await this.atomicPhase_(async (manager: EntityManager) => {
|
||||
@@ -404,9 +561,9 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
return payCol
|
||||
}
|
||||
|
||||
// If cart total is 0, we don't perform anything payment related
|
||||
if (payCol.amount <= 0) {
|
||||
payCol.authorized_amount = 0
|
||||
payCol.status = PaymentCollectionStatus.AUTHORIZED
|
||||
return await paymentCollectionRepository.save(payCol)
|
||||
}
|
||||
|
||||
@@ -426,6 +583,10 @@ export default class PaymentCollectionService extends TransactionBaseService {
|
||||
continue
|
||||
}
|
||||
|
||||
if (!sessionIds.includes(session.id)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const auth = await this.paymentProviderService_
|
||||
.withTransaction(manager)
|
||||
.authorizePayment(session, context)
|
||||
|
||||
@@ -349,6 +349,15 @@ export default class PaymentProviderService extends TransactionBaseService {
|
||||
})
|
||||
}
|
||||
|
||||
async deleteSessionNew(paymentSession: PaymentSession): Promise<void> {
|
||||
return await this.atomicPhase_(async (transactionManager) => {
|
||||
const provider = this.retrieveProvider(paymentSession.provider_id)
|
||||
return await provider
|
||||
.withTransaction(transactionManager)
|
||||
.deletePayment(paymentSession)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a provider given an id
|
||||
* @param {string} providerId - the id of the provider to get
|
||||
|
||||
@@ -52,6 +52,12 @@ export default class PaymentService extends TransactionBaseService {
|
||||
this.eventBusService_ = eventBusService
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a payment by id.
|
||||
* @param paymentId - the id of the payment
|
||||
* @param config - the config to retrieve the payment
|
||||
* @return the payment.
|
||||
*/
|
||||
async retrieve(
|
||||
paymentId: string,
|
||||
config: FindConfig<Payment> = {}
|
||||
@@ -75,6 +81,11 @@ export default class PaymentService extends TransactionBaseService {
|
||||
return payment[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Created a new payment.
|
||||
* @param paymentInput - info to create the payment
|
||||
* @return the payment created.
|
||||
*/
|
||||
async create(paymentInput: PaymentDataInput): Promise<Payment> {
|
||||
return await this.atomicPhase_(async (manager: EntityManager) => {
|
||||
const { data, currency_code, amount, provider_id } = paymentInput
|
||||
@@ -100,6 +111,12 @@ export default class PaymentService extends TransactionBaseService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a payment in order to link it to an order or a swap.
|
||||
* @param paymentId - the id of the payment
|
||||
* @param data - order_id or swap_id to link the payment
|
||||
* @return the payment updated.
|
||||
*/
|
||||
async update(
|
||||
paymentId: string,
|
||||
data: { order_id?: string; swap_id?: string }
|
||||
@@ -129,6 +146,11 @@ export default class PaymentService extends TransactionBaseService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures a payment.
|
||||
* @param paymentOrId - the id or the class instance of the payment
|
||||
* @return the payment captured.
|
||||
*/
|
||||
async capture(paymentOrId: string | Payment): Promise<Payment> {
|
||||
const payment =
|
||||
typeof paymentOrId === "string"
|
||||
@@ -170,6 +192,14 @@ export default class PaymentService extends TransactionBaseService {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* refunds a payment.
|
||||
* @param paymentOrId - the id or the class instance of the payment
|
||||
* @param amount - the amount to be refunded from the payment
|
||||
* @param reason - the refund reason
|
||||
* @param note - additional note of the refund
|
||||
* @return the refund created.
|
||||
*/
|
||||
async refund(
|
||||
paymentOrId: string | Payment,
|
||||
amount: number,
|
||||
|
||||
@@ -15,22 +15,24 @@ export type CreatePaymentCollectionInput = {
|
||||
description?: string
|
||||
}
|
||||
|
||||
export type PaymentCollectionSessionInput = {
|
||||
export type PaymentCollectionsSessionsBatchInput = {
|
||||
provider_id: string
|
||||
amount: number
|
||||
session_id?: string
|
||||
customer_id: string
|
||||
}
|
||||
|
||||
export type PaymentCollectionsSessionsInput = {
|
||||
provider_id: string
|
||||
}
|
||||
|
||||
export type PaymentProviderDataInput = {
|
||||
resource_id: string
|
||||
customer: Partial<Customer>
|
||||
customer: Partial<Customer> | null
|
||||
currency_code: string
|
||||
provider_id: string
|
||||
amount: number
|
||||
cart_id?: string
|
||||
cart?: Cart
|
||||
metadata?: any
|
||||
}
|
||||
export const defaultPaymentCollectionRelations = [
|
||||
"region",
|
||||
|
||||
Reference in New Issue
Block a user