Files
medusa-store/packages/payment/src/services/payment-provider.ts
2024-04-06 17:41:54 +02:00

216 lines
6.0 KiB
TypeScript

import {
Context,
CreatePaymentProviderDTO,
CreatePaymentProviderSession,
DAL,
FilterablePaymentProviderProps,
FindConfig,
InternalModuleDeclaration,
IPaymentProvider,
PaymentProviderAuthorizeResponse,
PaymentProviderDataInput,
PaymentProviderDTO,
PaymentProviderError,
PaymentProviderSessionResponse,
PaymentSessionStatus,
ProviderWebhookPayload,
UpdatePaymentProviderSession,
WebhookActionResult,
} from "@medusajs/types"
import {
InjectManager,
InjectTransactionManager,
isPaymentProviderError,
MedusaContext,
ModulesSdkUtils,
} from "@medusajs/utils"
import { PaymentProvider } from "@models"
import { MedusaError } from "medusa-core-utils"
import { EOL } from "os"
type InjectedDependencies = {
paymentProviderRepository: DAL.RepositoryService
[key: `pp_${string}`]: IPaymentProvider
}
export default class PaymentProviderService {
protected readonly container_: InjectedDependencies
protected readonly paymentProviderRepository_: DAL.RepositoryService
constructor(
container: InjectedDependencies,
protected readonly moduleDeclaration: InternalModuleDeclaration
) {
this.container_ = container
this.paymentProviderRepository_ = container.paymentProviderRepository
}
@InjectTransactionManager("paymentProviderRepository_")
async create(
data: CreatePaymentProviderDTO[],
@MedusaContext() sharedContext?: Context
): Promise<PaymentProvider[]> {
return await this.paymentProviderRepository_.create(data, sharedContext)
}
@InjectManager("paymentProviderRepository_")
async list(
filters: FilterablePaymentProviderProps,
config: FindConfig<PaymentProviderDTO>,
@MedusaContext() sharedContext?: Context
): Promise<PaymentProvider[]> {
const queryOptions = ModulesSdkUtils.buildQuery<PaymentProvider>(
filters,
config
)
return await this.paymentProviderRepository_.find(
queryOptions,
sharedContext
)
}
@InjectManager("paymentProviderRepository_")
async listAndCount(
filters: FilterablePaymentProviderProps,
config: FindConfig<PaymentProviderDTO>,
@MedusaContext() sharedContext?: Context
): Promise<[PaymentProvider[], number]> {
const queryOptions = ModulesSdkUtils.buildQuery<PaymentProvider>(
filters,
config
)
return await this.paymentProviderRepository_.findAndCount(
queryOptions,
sharedContext
)
}
retrieveProvider(providerId: string): IPaymentProvider {
try {
return this.container_[providerId] as IPaymentProvider
} catch (e) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`Could not find a payment provider with id: ${providerId}`
)
}
}
async createSession(
providerId: string,
sessionInput: CreatePaymentProviderSession
): Promise<PaymentProviderSessionResponse["data"]> {
const provider = this.retrieveProvider(providerId)
const paymentResponse = await provider.initiatePayment(sessionInput)
if (isPaymentProviderError(paymentResponse)) {
this.throwPaymentProviderError(paymentResponse)
}
return (paymentResponse as PaymentProviderSessionResponse).data
}
async updateSession(
providerId: string,
sessionInput: UpdatePaymentProviderSession
): Promise<Record<string, unknown> | undefined> {
const provider = this.retrieveProvider(providerId)
const paymentResponse = await provider.updatePayment(sessionInput)
if (isPaymentProviderError(paymentResponse)) {
this.throwPaymentProviderError(paymentResponse)
}
return (paymentResponse as PaymentProviderSessionResponse)?.data
}
async deleteSession(input: PaymentProviderDataInput): Promise<void> {
const provider = this.retrieveProvider(input.provider_id)
const error = await provider.deletePayment(input.data)
if (isPaymentProviderError(error)) {
this.throwPaymentProviderError(error)
}
}
async authorizePayment(
input: PaymentProviderDataInput,
context: Record<string, unknown>
): Promise<{ data: Record<string, unknown>; status: PaymentSessionStatus }> {
const provider = this.retrieveProvider(input.provider_id)
const res = await provider.authorizePayment(input.data, context)
if (isPaymentProviderError(res)) {
this.throwPaymentProviderError(res)
}
const { data, status } = res as PaymentProviderAuthorizeResponse
return { data, status }
}
async getStatus(
input: PaymentProviderDataInput
): Promise<PaymentSessionStatus> {
const provider = this.retrieveProvider(input.provider_id)
return await provider.getPaymentStatus(input.data)
}
async capturePayment(
input: PaymentProviderDataInput
): Promise<Record<string, unknown>> {
const provider = this.retrieveProvider(input.provider_id)
const res = await provider.capturePayment(input.data)
if (isPaymentProviderError(res)) {
this.throwPaymentProviderError(res)
}
return res as Record<string, unknown>
}
async cancelPayment(input: PaymentProviderDataInput): Promise<void> {
const provider = this.retrieveProvider(input.provider_id)
const error = await provider.cancelPayment(input.data)
if (isPaymentProviderError(error)) {
this.throwPaymentProviderError(error)
}
}
async refundPayment(
input: PaymentProviderDataInput,
amount: number
): Promise<Record<string, unknown>> {
const provider = this.retrieveProvider(input.provider_id)
const res = await provider.refundPayment(input.data, amount)
if (isPaymentProviderError(res)) {
this.throwPaymentProviderError(res)
}
return res as Record<string, unknown>
}
async getWebhookActionAndData(
providerId: string,
data: ProviderWebhookPayload["payload"]
): Promise<WebhookActionResult> {
const provider = this.retrieveProvider(providerId)
return await provider.getWebhookActionAndData(data)
}
private throwPaymentProviderError(errObj: PaymentProviderError) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`${errObj.error}${errObj.detail ? `:${EOL}${errObj.detail}` : ""}`,
errObj.code
)
}
}