feat: Consolidate payment functions and handle sessions for storefront (#7231)
This commit is contained in:
@@ -1455,8 +1455,13 @@ medusaIntegrationTestRunner({
|
|||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
operator: RuleOperator.EQ,
|
operator: RuleOperator.EQ,
|
||||||
attribute: "shipping_address.province",
|
attribute: "is_return",
|
||||||
value: "ny",
|
value: "false",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
operator: RuleOperator.EQ,
|
||||||
|
attribute: "enabled_in_store",
|
||||||
|
value: "true",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1197,7 +1197,7 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("POST /store/carts/:id/payment-collections", () => {
|
describe("POST /store/payment-collections", () => {
|
||||||
it("should create a payment collection for the cart", async () => {
|
it("should create a payment collection for the cart", async () => {
|
||||||
const region = await regionModule.create({
|
const region = await regionModule.create({
|
||||||
name: "US",
|
name: "US",
|
||||||
@@ -1209,22 +1209,92 @@ medusaIntegrationTestRunner({
|
|||||||
region_id: region.id,
|
region_id: region.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
const response = await api.post(
|
const response = await api.post(`/store/payment-collections`, {
|
||||||
`/store/carts/${cart.id}/payment-collections`
|
region_id: region.id,
|
||||||
)
|
cart_id: cart.id,
|
||||||
|
amount: 0,
|
||||||
|
currency_code: cart.currency_code,
|
||||||
|
})
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.cart).toEqual(
|
expect(response.data.payment_collection).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: cart.id,
|
id: expect.any(String),
|
||||||
currency_code: "usd",
|
amount: 0,
|
||||||
payment_collection: expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
amount: 0,
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should return an existing payment collection for the cart", async () => {
|
||||||
|
const region = await regionModule.create({
|
||||||
|
name: "US",
|
||||||
|
currency_code: "usd",
|
||||||
|
})
|
||||||
|
|
||||||
|
const cart = await cartModule.create({
|
||||||
|
currency_code: "usd",
|
||||||
|
region_id: region.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
const firstCollection = (
|
||||||
|
await api.post(`/store/payment-collections`, {
|
||||||
|
region_id: region.id,
|
||||||
|
cart_id: cart.id,
|
||||||
|
amount: 0,
|
||||||
|
currency_code: cart.currency_code,
|
||||||
|
})
|
||||||
|
).data.payment_collection
|
||||||
|
|
||||||
|
const response = await api.post(`/store/payment-collections`, {
|
||||||
|
region_id: region.id,
|
||||||
|
cart_id: cart.id,
|
||||||
|
amount: 0,
|
||||||
|
currency_code: cart.currency_code,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.payment_collection.id).toEqual(
|
||||||
|
firstCollection.id
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create a new payment collection for a new cart", async () => {
|
||||||
|
const region = await regionModule.create({
|
||||||
|
name: "US",
|
||||||
|
currency_code: "usd",
|
||||||
|
})
|
||||||
|
|
||||||
|
const firstCart = await cartModule.create({
|
||||||
|
currency_code: "usd",
|
||||||
|
region_id: region.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
const secondCart = await cartModule.create({
|
||||||
|
currency_code: "usd",
|
||||||
|
region_id: region.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
const firstCollection = (
|
||||||
|
await api.post(`/store/payment-collections`, {
|
||||||
|
region_id: region.id,
|
||||||
|
cart_id: firstCart.id,
|
||||||
|
amount: 0,
|
||||||
|
currency_code: firstCart.currency_code,
|
||||||
|
})
|
||||||
|
).data.payment_collection
|
||||||
|
|
||||||
|
const secondCollection = (
|
||||||
|
await api.post(`/store/payment-collections`, {
|
||||||
|
region_id: region.id,
|
||||||
|
cart_id: secondCart.id,
|
||||||
|
amount: 0,
|
||||||
|
currency_code: secondCart.currency_code,
|
||||||
|
})
|
||||||
|
).data.payment_collection
|
||||||
|
|
||||||
|
expect(firstCollection.id).toBeTruthy()
|
||||||
|
expect(firstCollection.id).not.toEqual(secondCollection.id)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("POST /store/carts/:id/taxes", () => {
|
describe("POST /store/carts/:id/taxes", () => {
|
||||||
@@ -1363,8 +1433,13 @@ medusaIntegrationTestRunner({
|
|||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
operator: RuleOperator.EQ,
|
operator: RuleOperator.EQ,
|
||||||
attribute: "shipping_address.country_code",
|
attribute: "is_return",
|
||||||
value: "us",
|
value: "false",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
operator: RuleOperator.EQ,
|
||||||
|
attribute: "enabled_in_store",
|
||||||
|
value: "true",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
+6
-2
@@ -5,6 +5,10 @@ import { createStep, StepResponse } from "@medusajs/workflows-sdk"
|
|||||||
|
|
||||||
interface StepInput {
|
interface StepInput {
|
||||||
cart: CartDTO
|
cart: CartDTO
|
||||||
|
shippingOptionsContext: {
|
||||||
|
enabled_in_store?: "true" | "false"
|
||||||
|
is_return?: "true" | "false"
|
||||||
|
}
|
||||||
option_ids: string[]
|
option_ids: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,7 +17,7 @@ export const validateCartShippingOptionsStepId =
|
|||||||
export const validateCartShippingOptionsStep = createStep(
|
export const validateCartShippingOptionsStep = createStep(
|
||||||
validateCartShippingOptionsStepId,
|
validateCartShippingOptionsStepId,
|
||||||
async (data: StepInput, { container }) => {
|
async (data: StepInput, { container }) => {
|
||||||
const { option_ids: optionIds = [], cart } = data
|
const { option_ids: optionIds = [], cart, shippingOptionsContext } = data
|
||||||
|
|
||||||
if (!optionIds.length) {
|
if (!optionIds.length) {
|
||||||
return new StepResponse(void 0)
|
return new StepResponse(void 0)
|
||||||
@@ -27,7 +31,7 @@ export const validateCartShippingOptionsStep = createStep(
|
|||||||
await fulfillmentModule.listShippingOptionsForContext(
|
await fulfillmentModule.listShippingOptionsForContext(
|
||||||
{
|
{
|
||||||
id: optionIds,
|
id: optionIds,
|
||||||
context: { ...cart },
|
context: shippingOptionsContext,
|
||||||
address: {
|
address: {
|
||||||
country_code: cart.shipping_address?.country_code,
|
country_code: cart.shipping_address?.country_code,
|
||||||
province_code: cart.shipping_address?.province,
|
province_code: cart.shipping_address?.province,
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export const addShippingMethodToWorkflow = createWorkflow(
|
|||||||
validateCartShippingOptionsStep({
|
validateCartShippingOptionsStep({
|
||||||
option_ids: optionIds,
|
option_ids: optionIds,
|
||||||
cart,
|
cart,
|
||||||
|
shippingOptionsContext: { is_return: "false", enabled_in_store: "true" },
|
||||||
})
|
})
|
||||||
|
|
||||||
const shippingOptions = useRemoteQueryStep({
|
const shippingOptions = useRemoteQueryStep({
|
||||||
|
|||||||
+4
@@ -46,6 +46,10 @@ export const listShippingOptionsForCartWorkflow = createWorkflow(
|
|||||||
variables: {
|
variables: {
|
||||||
id: input.sales_channel_id,
|
id: input.sales_channel_id,
|
||||||
"stock_locations.fulfillment_sets.service_zones.shipping_options": {
|
"stock_locations.fulfillment_sets.service_zones.shipping_options": {
|
||||||
|
context: {
|
||||||
|
is_return: "false",
|
||||||
|
enabled_in_store: "true",
|
||||||
|
},
|
||||||
filters: {
|
filters: {
|
||||||
address: {
|
address: {
|
||||||
city: input.shipping_address?.city,
|
city: input.shipping_address?.city,
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ import { storeCustomerRoutesMiddlewares } from "./store/customers/middlewares"
|
|||||||
import { storeProductRoutesMiddlewares } from "./store/products/middlewares"
|
import { storeProductRoutesMiddlewares } from "./store/products/middlewares"
|
||||||
import { storeProductCategoryRoutesMiddlewares } from "./store/product-categories/middlewares"
|
import { storeProductCategoryRoutesMiddlewares } from "./store/product-categories/middlewares"
|
||||||
import { storeRegionRoutesMiddlewares } from "./store/regions/middlewares"
|
import { storeRegionRoutesMiddlewares } from "./store/regions/middlewares"
|
||||||
|
import { storePaymentProvidersMiddlewares } from "./store/payment-providers/middlewares"
|
||||||
|
import { storePaymentCollectionsMiddlewares } from "./store/payment-collections/middlewares"
|
||||||
|
import { storeShippingOptionRoutesMiddlewares } from "./store/shipping-options/middlewares"
|
||||||
|
|
||||||
export const config: MiddlewaresConfig = {
|
export const config: MiddlewaresConfig = {
|
||||||
routes: [
|
routes: [
|
||||||
@@ -52,6 +55,9 @@ export const config: MiddlewaresConfig = {
|
|||||||
...storeCartRoutesMiddlewares,
|
...storeCartRoutesMiddlewares,
|
||||||
...storeCollectionRoutesMiddlewares,
|
...storeCollectionRoutesMiddlewares,
|
||||||
...storeProductCategoryRoutesMiddlewares,
|
...storeProductCategoryRoutesMiddlewares,
|
||||||
|
...storePaymentProvidersMiddlewares,
|
||||||
|
...storeShippingOptionRoutesMiddlewares,
|
||||||
|
...storePaymentCollectionsMiddlewares,
|
||||||
...authRoutesMiddlewares,
|
...authRoutesMiddlewares,
|
||||||
...adminWorkflowsExecutionsMiddlewares,
|
...adminWorkflowsExecutionsMiddlewares,
|
||||||
...storeRegionRoutesMiddlewares,
|
...storeRegionRoutesMiddlewares,
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
import { createPaymentCollectionForCartWorkflow } from "@medusajs/core-flows"
|
|
||||||
import { MedusaRequest, MedusaResponse } from "../../../../../types/routing"
|
|
||||||
import { refetchCart } from "../../helpers"
|
|
||||||
import { StoreUpdateCartType } from "../../validators"
|
|
||||||
|
|
||||||
export const POST = async (
|
|
||||||
req: MedusaRequest<StoreUpdateCartType>,
|
|
||||||
res: MedusaResponse
|
|
||||||
) => {
|
|
||||||
const workflow = createPaymentCollectionForCartWorkflow(req.scope)
|
|
||||||
let cart = await refetchCart(req.params.id, req.scope, [
|
|
||||||
"id",
|
|
||||||
"currency_code",
|
|
||||||
"region_id",
|
|
||||||
"total",
|
|
||||||
])
|
|
||||||
|
|
||||||
const { errors } = await workflow.run({
|
|
||||||
input: {
|
|
||||||
cart_id: req.params.id,
|
|
||||||
region_id: cart.region_id,
|
|
||||||
currency_code: cart.currency_code,
|
|
||||||
amount: cart.total ?? 0, // TODO: This should be calculated from the cart when totals decoration is introduced
|
|
||||||
},
|
|
||||||
throwOnError: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (Array.isArray(errors) && errors[0]) {
|
|
||||||
throw errors[0].error
|
|
||||||
}
|
|
||||||
|
|
||||||
cart = await refetchCart(
|
|
||||||
req.params.id,
|
|
||||||
req.scope,
|
|
||||||
req.remoteQueryConfig.fields
|
|
||||||
)
|
|
||||||
|
|
||||||
res.status(200).json({ cart })
|
|
||||||
}
|
|
||||||
@@ -114,17 +114,6 @@ export const storeCartRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
method: ["POST"],
|
|
||||||
matcher: "/store/carts/:id/payment-collections",
|
|
||||||
middlewares: [
|
|
||||||
validateAndTransformBody(StoreUpdateCart),
|
|
||||||
validateAndTransformQuery(
|
|
||||||
StoreGetCartsCart,
|
|
||||||
QueryConfig.retrieveTransformQueryConfig
|
|
||||||
),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
method: ["POST"],
|
method: ["POST"],
|
||||||
matcher: "/store/carts/:id/shipping-methods",
|
matcher: "/store/carts/:id/shipping-methods",
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ export const defaultStoreCartFields = [
|
|||||||
"shipping_methods.tax_lines.code",
|
"shipping_methods.tax_lines.code",
|
||||||
"shipping_methods.tax_lines.rate",
|
"shipping_methods.tax_lines.rate",
|
||||||
"shipping_methods.tax_lines.provider_id",
|
"shipping_methods.tax_lines.provider_id",
|
||||||
"shipping_methods.shipping_option_id",
|
|
||||||
"shipping_methods.amount",
|
"shipping_methods.amount",
|
||||||
"shipping_methods.adjustments.id",
|
"shipping_methods.adjustments.id",
|
||||||
"shipping_methods.adjustments.code",
|
"shipping_methods.adjustments.code",
|
||||||
"shipping_methods.adjustments.amount",
|
"shipping_methods.adjustments.amount",
|
||||||
|
"shipping_methods.shipping_option_id",
|
||||||
"shipping_address.id",
|
"shipping_address.id",
|
||||||
"shipping_address.first_name",
|
"shipping_address.first_name",
|
||||||
"shipping_address.last_name",
|
"shipping_address.last_name",
|
||||||
@@ -86,18 +86,16 @@ export const defaultStoreCartFields = [
|
|||||||
"region.name",
|
"region.name",
|
||||||
"region.currency_code",
|
"region.currency_code",
|
||||||
"region.automatic_taxes",
|
"region.automatic_taxes",
|
||||||
|
"*region.countries",
|
||||||
"sales_channel_id",
|
"sales_channel_id",
|
||||||
|
|
||||||
// TODO: To be updated when payment sessions are introduces in the Rest API
|
// TODO: To be updated when payment sessions are introduces in the Rest API
|
||||||
"payment_collection.id",
|
"payment_collection.id",
|
||||||
"payment_collection.amount",
|
"payment_collection.amount",
|
||||||
"payment_collection.payment_sessions",
|
"*payment_collection.payment_sessions",
|
||||||
]
|
]
|
||||||
|
|
||||||
const allowedFields = [...defaultStoreCartFields]
|
|
||||||
|
|
||||||
export const retrieveTransformQueryConfig = {
|
export const retrieveTransformQueryConfig = {
|
||||||
defaults: defaultStoreCartFields,
|
defaults: defaultStoreCartFields,
|
||||||
allowed: allowedFields,
|
|
||||||
isList: false,
|
isList: false,
|
||||||
}
|
}
|
||||||
|
|||||||
-11
@@ -1,11 +0,0 @@
|
|||||||
import { transformBody } from "../../../../../api/middlewares"
|
|
||||||
import { MiddlewareRoute } from "../../../../../loaders/helpers/routing/types"
|
|
||||||
import { StorePostPaymentCollectionsPaymentSessionReq } from "./validators"
|
|
||||||
|
|
||||||
export const storeCartRoutesMiddlewares: MiddlewareRoute[] = [
|
|
||||||
{
|
|
||||||
method: ["POST"],
|
|
||||||
matcher: "/store/payment-collections/:id/payment-sessions",
|
|
||||||
middlewares: [transformBody(StorePostPaymentCollectionsPaymentSessionReq)],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
-20
@@ -1,20 +0,0 @@
|
|||||||
export const defaultStorePaymentCollectionFields = [
|
|
||||||
"id",
|
|
||||||
"currency_code",
|
|
||||||
"amount",
|
|
||||||
"payment_sessions",
|
|
||||||
"payment_sessions.id",
|
|
||||||
"payment_sessions.amount",
|
|
||||||
"payment_sessions.provider_id",
|
|
||||||
]
|
|
||||||
|
|
||||||
export const defaultStorePaymentCollectionRelations = ["payment_sessions"]
|
|
||||||
|
|
||||||
export const allowedStorePaymentCollectionRelations = ["payment_sessions"]
|
|
||||||
|
|
||||||
export const retrieveTransformQueryConfig = {
|
|
||||||
defaultFields: defaultStorePaymentCollectionFields,
|
|
||||||
defaultRelations: defaultStorePaymentCollectionRelations,
|
|
||||||
allowedRelations: allowedStorePaymentCollectionRelations,
|
|
||||||
isList: false,
|
|
||||||
}
|
|
||||||
+14
-21
@@ -1,36 +1,33 @@
|
|||||||
import { createPaymentSessionsWorkflow } from "@medusajs/core-flows"
|
import { createPaymentSessionsWorkflow } from "@medusajs/core-flows"
|
||||||
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
|
||||||
import {
|
import {
|
||||||
AuthenticatedMedusaRequest,
|
AuthenticatedMedusaRequest,
|
||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../../../types/routing"
|
} from "../../../../../types/routing"
|
||||||
import { defaultStorePaymentCollectionFields } from "./query-config"
|
import { StoreCreatePaymentSessionType } from "../../validators"
|
||||||
import { StorePostPaymentCollectionsPaymentSessionReq } from "./validators"
|
import { refetchPaymentCollection } from "../../helpers"
|
||||||
|
|
||||||
export const POST = async (
|
export const POST = async (
|
||||||
req: AuthenticatedMedusaRequest<StorePostPaymentCollectionsPaymentSessionReq>,
|
req: AuthenticatedMedusaRequest<StoreCreatePaymentSessionType>,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const { id } = req.params
|
const collectionId = req.params.id
|
||||||
const { context = {}, provider_id, data } = req.body
|
const { context = {}, data, provider_id } = req.body
|
||||||
|
|
||||||
// If the customer is logged in, we auto-assign them to the payment collection
|
// If the customer is logged in, we auto-assign them to the payment collection
|
||||||
if (req.auth?.actor_id) {
|
if (req.auth?.actor_id) {
|
||||||
context.customer = {
|
;(context as any).customer = {
|
||||||
...context.customer,
|
|
||||||
id: req.auth.actor_id,
|
id: req.auth.actor_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const workflowInput = {
|
const workflowInput = {
|
||||||
payment_collection_id: id,
|
payment_collection_id: collectionId,
|
||||||
provider_id: provider_id,
|
provider_id: provider_id,
|
||||||
data,
|
data,
|
||||||
context,
|
context,
|
||||||
}
|
}
|
||||||
|
|
||||||
const { errors } = await createPaymentSessionsWorkflow(req.scope).run({
|
const { errors } = await createPaymentSessionsWorkflow(req.scope).run({
|
||||||
input: workflowInput as any,
|
input: workflowInput,
|
||||||
throwOnError: false,
|
throwOnError: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -38,15 +35,11 @@ export const POST = async (
|
|||||||
throw errors[0].error
|
throw errors[0].error
|
||||||
}
|
}
|
||||||
|
|
||||||
const remoteQuery = req.scope.resolve("remoteQuery")
|
const paymentCollection = await refetchPaymentCollection(
|
||||||
|
collectionId,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
const query = remoteQueryObjectFromString({
|
res.status(200).json({ payment_collection: paymentCollection })
|
||||||
entryPoint: "payment_collection",
|
|
||||||
variables: { cart: { id } },
|
|
||||||
fields: defaultStorePaymentCollectionFields,
|
|
||||||
})
|
|
||||||
|
|
||||||
const [result] = await remoteQuery(query)
|
|
||||||
|
|
||||||
res.status(200).json({ payment_collection: result })
|
|
||||||
}
|
}
|
||||||
|
|||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
import { PaymentProviderContext } from "@medusajs/types"
|
|
||||||
|
|
||||||
export class StorePostPaymentCollectionsPaymentSessionReq {
|
|
||||||
provider_id: string
|
|
||||||
context?: PaymentProviderContext
|
|
||||||
data?: Record<string, unknown>
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { MedusaContainer, PaymentCollectionDTO } from "@medusajs/types"
|
||||||
|
import { refetchEntity } from "../../utils/refetch-entity"
|
||||||
|
|
||||||
|
export const refetchPaymentCollection = async (
|
||||||
|
id: string,
|
||||||
|
scope: MedusaContainer,
|
||||||
|
fields: string[]
|
||||||
|
): Promise<PaymentCollectionDTO> => {
|
||||||
|
return refetchEntity("payment_collection", id, scope, fields)
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { MiddlewareRoute } from "../../../types/middlewares"
|
||||||
|
import { authenticate } from "../../../utils/authenticate-middleware"
|
||||||
|
import { validateAndTransformBody } from "../../utils/validate-body"
|
||||||
|
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||||
|
import * as queryConfig from "./query-config"
|
||||||
|
import {
|
||||||
|
StoreGetPaymentCollectionParams,
|
||||||
|
StoreCreatePaymentCollection,
|
||||||
|
StoreCreatePaymentSession,
|
||||||
|
} from "./validators"
|
||||||
|
|
||||||
|
export const storePaymentCollectionsMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: "ALL",
|
||||||
|
matcher: "/store/payment-collections*",
|
||||||
|
middlewares: [
|
||||||
|
authenticate("store", ["session", "bearer"], {
|
||||||
|
allowUnauthenticated: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/store/payment-collections",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(StoreCreatePaymentCollection),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreGetPaymentCollectionParams,
|
||||||
|
queryConfig.retrievePaymentCollectionTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/store/payment-collections/:id/payment-sessions",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(StoreCreatePaymentSession),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreGetPaymentCollectionParams,
|
||||||
|
queryConfig.retrievePaymentCollectionTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
export const defaultPaymentCollectionFields = [
|
||||||
|
"id",
|
||||||
|
"currency_code",
|
||||||
|
"amount",
|
||||||
|
"payment_sessions",
|
||||||
|
"payment_sessions.id",
|
||||||
|
"payment_sessions.amount",
|
||||||
|
"payment_sessions.provider_id",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const retrievePaymentCollectionTransformQueryConfig = {
|
||||||
|
defaults: defaultPaymentCollectionFields,
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { createPaymentCollectionForCartWorkflow } from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../types/routing"
|
||||||
|
import { StoreCreatePaymentCollectionType } from "./validators"
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<StoreCreatePaymentCollectionType>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
const { cart_id } = req.body
|
||||||
|
|
||||||
|
// We can potentially refactor the workflow to behave more like an upsert and return an existing collection if there is one.
|
||||||
|
const [cartCollectionRelation] = await remoteQuery(
|
||||||
|
remoteQueryObjectFromString({
|
||||||
|
entryPoint: "cart_payment_collection",
|
||||||
|
variables: { filters: { cart_id } },
|
||||||
|
fields: req.remoteQueryConfig.fields.map(
|
||||||
|
(f) => `payment_collection.${f}`
|
||||||
|
),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
let paymentCollection = cartCollectionRelation?.payment_collection
|
||||||
|
|
||||||
|
if (!paymentCollection) {
|
||||||
|
const { errors } = await createPaymentCollectionForCartWorkflow(
|
||||||
|
req.scope
|
||||||
|
).run({
|
||||||
|
input: req.body,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
const [cartCollectionRelation] = await remoteQuery(
|
||||||
|
remoteQueryObjectFromString({
|
||||||
|
entryPoint: "cart_payment_collection",
|
||||||
|
variables: { filters: { cart_id } },
|
||||||
|
fields: req.remoteQueryConfig.fields.map(
|
||||||
|
(f) => `payment_collection.${f}`
|
||||||
|
),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
paymentCollection = cartCollectionRelation?.payment_collection
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({ payment_collection: paymentCollection })
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { createSelectParams } from "../../utils/validators"
|
||||||
|
|
||||||
|
export type StoreGetPaymentCollectionParamsType = z.infer<
|
||||||
|
typeof StoreGetPaymentCollectionParams
|
||||||
|
>
|
||||||
|
export const StoreGetPaymentCollectionParams = createSelectParams()
|
||||||
|
|
||||||
|
export type StoreCreatePaymentSessionType = z.infer<
|
||||||
|
typeof StoreCreatePaymentSession
|
||||||
|
>
|
||||||
|
export const StoreCreatePaymentSession = z
|
||||||
|
.object({
|
||||||
|
provider_id: z.string(),
|
||||||
|
context: z.record(z.unknown()).optional(),
|
||||||
|
data: z.record(z.unknown()).optional(),
|
||||||
|
})
|
||||||
|
.strict()
|
||||||
|
|
||||||
|
export type StoreCreatePaymentCollectionType = z.infer<
|
||||||
|
typeof StoreCreatePaymentCollection
|
||||||
|
>
|
||||||
|
export const StoreCreatePaymentCollection = z
|
||||||
|
.object({
|
||||||
|
cart_id: z.string(),
|
||||||
|
region_id: z.string(),
|
||||||
|
currency_code: z.string(),
|
||||||
|
amount: z.number(),
|
||||||
|
})
|
||||||
|
.strict()
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { MiddlewareRoute } from "../../../types/middlewares"
|
||||||
|
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||||
|
import * as queryConfig from "./query-config"
|
||||||
|
import { StoreGetPaymentProvidersParams } from "./validators"
|
||||||
|
|
||||||
|
export const storePaymentProvidersMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/store/payment-providers",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreGetPaymentProvidersParams,
|
||||||
|
queryConfig.listTransformPaymentProvidersQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export const defaultAdminPaymentProviderFields = ["id", "is_enabled"]
|
||||||
|
|
||||||
|
export const listTransformPaymentProvidersQueryConfig = {
|
||||||
|
defaults: defaultAdminPaymentProviderFields,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../types/routing"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
MedusaError,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import { StoreGetPaymentProvidersParamsType } from "./validators"
|
||||||
|
|
||||||
|
// TODO: Add more fields to provider, such as default name and maybe logo.
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest<StoreGetPaymentProvidersParamsType>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
if (!req.filterableFields.region_id) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_ALLOWED,
|
||||||
|
"You must provide the region_id to list payment providers"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "region_payment_provider",
|
||||||
|
variables: {
|
||||||
|
filters: {
|
||||||
|
region_id: req.filterableFields.region_id,
|
||||||
|
},
|
||||||
|
...req.remoteQueryConfig.pagination,
|
||||||
|
},
|
||||||
|
fields: req.remoteQueryConfig.fields.map((f) => `payment_provider.${f}`),
|
||||||
|
})
|
||||||
|
|
||||||
|
const { rows: regionPaymentProvidersRelation, metadata } = await remoteQuery(
|
||||||
|
queryObject
|
||||||
|
)
|
||||||
|
|
||||||
|
const paymentProviders = regionPaymentProvidersRelation.map(
|
||||||
|
(relation) => relation.payment_provider
|
||||||
|
)
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
payment_providers: paymentProviders,
|
||||||
|
count: metadata.count,
|
||||||
|
offset: metadata.skip,
|
||||||
|
limit: metadata.take,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { createFindParams } from "../../utils/validators"
|
||||||
|
|
||||||
|
export type StoreGetPaymentProvidersParamsType = z.infer<
|
||||||
|
typeof StoreGetPaymentProvidersParams
|
||||||
|
>
|
||||||
|
export const StoreGetPaymentProvidersParams = createFindParams({
|
||||||
|
limit: 20,
|
||||||
|
offset: 0,
|
||||||
|
}).merge(
|
||||||
|
z.object({
|
||||||
|
region_id: z.string(),
|
||||||
|
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
is_enabled: z.boolean().optional(),
|
||||||
|
$and: z.lazy(() => StoreGetPaymentProvidersParams.array()).optional(),
|
||||||
|
$or: z.lazy(() => StoreGetPaymentProvidersParams.array()).optional(),
|
||||||
|
})
|
||||||
|
)
|
||||||
@@ -1,9 +1,17 @@
|
|||||||
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
||||||
|
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||||
|
import { listTransformQueryConfig } from "./query-config"
|
||||||
|
import { StoreGetShippingOptions } from "./validators"
|
||||||
|
|
||||||
export const storeShippingOptionRoutesMiddlewares: MiddlewareRoute[] = [
|
export const storeShippingOptionRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
{
|
{
|
||||||
method: ["GET"],
|
method: ["GET"],
|
||||||
matcher: "/store/shipping-options/:cart_id",
|
matcher: "/store/shipping-options",
|
||||||
middlewares: [],
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreGetShippingOptions,
|
||||||
|
listTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
+9
-2
@@ -1,10 +1,17 @@
|
|||||||
import { listShippingOptionsForCartWorkflow } from "@medusajs/core-flows"
|
import { listShippingOptionsForCartWorkflow } from "@medusajs/core-flows"
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
import { ICartModuleService } from "@medusajs/types"
|
import { ICartModuleService } from "@medusajs/types"
|
||||||
import { MedusaRequest, MedusaResponse } from "../../../../types/routing"
|
import { MedusaRequest, MedusaResponse } from "../../../types/routing"
|
||||||
|
import { MedusaError } from "@medusajs/utils"
|
||||||
|
|
||||||
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||||
const { cart_id } = req.params
|
const { cart_id } = req.filterableFields as { cart_id: string }
|
||||||
|
if (!cart_id) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_ALLOWED,
|
||||||
|
"You must provide the cart_id to list shipping options"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const cartService = req.scope.resolve<ICartModuleService>(
|
const cartService = req.scope.resolve<ICartModuleService>(
|
||||||
ModuleRegistrationName.CART
|
ModuleRegistrationName.CART
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { createFindParams } from "../../utils/validators"
|
||||||
|
|
||||||
|
export type StoreGetShippingOptionsType = z.infer<
|
||||||
|
typeof StoreGetShippingOptions
|
||||||
|
>
|
||||||
|
export const StoreGetShippingOptions = createFindParams({
|
||||||
|
limit: 20,
|
||||||
|
offset: 0,
|
||||||
|
}).merge(
|
||||||
|
z.object({
|
||||||
|
cart_id: z.string(),
|
||||||
|
$and: z.lazy(() => StoreGetShippingOptions.array()).optional(),
|
||||||
|
$or: z.lazy(() => StoreGetShippingOptions.array()).optional(),
|
||||||
|
})
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user