747 lines
22 KiB
TypeScript
747 lines
22 KiB
TypeScript
import { isDefined, MedusaError } from "medusa-core-utils"
|
|
import { BasePaymentService } from "medusa-interfaces"
|
|
import { EntityManager } from "typeorm"
|
|
import {
|
|
AbstractPaymentService,
|
|
PaymentContext,
|
|
PaymentSessionResponse,
|
|
TransactionBaseService,
|
|
} from "../interfaces"
|
|
import {
|
|
Cart,
|
|
Payment,
|
|
PaymentProvider,
|
|
PaymentSession,
|
|
PaymentSessionStatus,
|
|
Refund,
|
|
} from "../models"
|
|
import { PaymentRepository } from "../repositories/payment"
|
|
import { PaymentProviderRepository } from "../repositories/payment-provider"
|
|
import { PaymentSessionRepository } from "../repositories/payment-session"
|
|
import { RefundRepository } from "../repositories/refund"
|
|
import { FindConfig, Selector } from "../types/common"
|
|
import { Logger } from "../types/global"
|
|
import { CreatePaymentInput, PaymentSessionInput } from "../types/payment"
|
|
import { buildQuery, isString } from "../utils"
|
|
import { FlagRouter } from "../utils/flag-router"
|
|
import { CustomerService } from "./index"
|
|
import PaymentService from "./payment"
|
|
|
|
type PaymentProviderKey = `pp_${string}` | "systemPaymentProviderService"
|
|
type InjectedDependencies = {
|
|
manager: EntityManager
|
|
paymentSessionRepository: typeof PaymentSessionRepository
|
|
paymentProviderRepository: typeof PaymentProviderRepository
|
|
paymentRepository: typeof PaymentRepository
|
|
refundRepository: typeof RefundRepository
|
|
paymentService: PaymentService
|
|
customerService: CustomerService
|
|
featureFlagRouter: FlagRouter
|
|
logger: Logger
|
|
} & {
|
|
[key in `${PaymentProviderKey}`]:
|
|
| AbstractPaymentService
|
|
| typeof BasePaymentService
|
|
}
|
|
|
|
/**
|
|
* Helps retrieve payment providers
|
|
*/
|
|
export default class PaymentProviderService extends TransactionBaseService {
|
|
protected readonly container_: InjectedDependencies
|
|
protected readonly paymentSessionRepository_: typeof PaymentSessionRepository
|
|
// eslint-disable-next-line max-len
|
|
protected readonly paymentProviderRepository_: typeof PaymentProviderRepository
|
|
protected readonly paymentRepository_: typeof PaymentRepository
|
|
protected readonly refundRepository_: typeof RefundRepository
|
|
protected readonly customerService_: CustomerService
|
|
protected readonly logger_: Logger
|
|
|
|
protected readonly featureFlagRouter_: FlagRouter
|
|
|
|
constructor(container: InjectedDependencies) {
|
|
super(container)
|
|
|
|
this.container_ = container
|
|
this.paymentSessionRepository_ = container.paymentSessionRepository
|
|
this.paymentProviderRepository_ = container.paymentProviderRepository
|
|
this.paymentRepository_ = container.paymentRepository
|
|
this.refundRepository_ = container.refundRepository
|
|
this.customerService_ = container.customerService
|
|
this.featureFlagRouter_ = container.featureFlagRouter
|
|
this.logger_ = container.logger
|
|
}
|
|
|
|
async registerInstalledProviders(providerIds: string[]): Promise<void> {
|
|
return await this.atomicPhase_(async (transactionManager) => {
|
|
const model = transactionManager.withRepository(
|
|
this.paymentProviderRepository_
|
|
)
|
|
await model.update({}, { is_installed: false })
|
|
|
|
await Promise.all(
|
|
providerIds.map(async (providerId) => {
|
|
const provider = model.create({
|
|
id: providerId,
|
|
is_installed: true,
|
|
})
|
|
return await model.save(provider)
|
|
})
|
|
)
|
|
})
|
|
}
|
|
|
|
async list(): Promise<PaymentProvider[]> {
|
|
const ppRepo = this.activeManager_.withRepository(
|
|
this.paymentProviderRepository_
|
|
)
|
|
return await ppRepo.find()
|
|
}
|
|
|
|
async retrievePayment(
|
|
id: string,
|
|
relations: string[] = []
|
|
): Promise<Payment | never> {
|
|
const paymentRepo = this.activeManager_.withRepository(
|
|
this.paymentRepository_
|
|
)
|
|
const query = {
|
|
where: { id },
|
|
relations: [] as string[],
|
|
}
|
|
|
|
if (relations.length) {
|
|
query.relations = relations
|
|
}
|
|
|
|
const payment = await paymentRepo.findOne(query)
|
|
|
|
if (!payment) {
|
|
throw new MedusaError(
|
|
MedusaError.Types.NOT_FOUND,
|
|
`Payment with ${id} was not found`
|
|
)
|
|
}
|
|
|
|
return payment
|
|
}
|
|
|
|
async listPayments(
|
|
selector: Selector<Payment>,
|
|
config: FindConfig<Payment> = {
|
|
skip: 0,
|
|
take: 50,
|
|
order: { created_at: "DESC" },
|
|
}
|
|
): Promise<Payment[]> {
|
|
const payRepo = this.activeManager_.withRepository(this.paymentRepository_)
|
|
const query = buildQuery(selector, config)
|
|
return await payRepo.find(query)
|
|
}
|
|
|
|
async retrieveSession(
|
|
id: string,
|
|
relations: string[] = []
|
|
): Promise<PaymentSession | never> {
|
|
const sessionRepo = this.activeManager_.withRepository(
|
|
this.paymentSessionRepository_
|
|
)
|
|
|
|
const query = {
|
|
where: { id },
|
|
relations: [] as string[],
|
|
}
|
|
|
|
if (relations.length) {
|
|
query.relations = relations
|
|
}
|
|
|
|
const session = await sessionRepo.findOne(query)
|
|
|
|
if (!session) {
|
|
throw new MedusaError(
|
|
MedusaError.Types.NOT_FOUND,
|
|
`Payment Session with ${id} was not found`
|
|
)
|
|
}
|
|
|
|
return session
|
|
}
|
|
|
|
/**
|
|
* Creates a payment session with the given provider.
|
|
* @param providerIdOrSessionInput - the id of the provider to create payment with or the input data
|
|
* @param cart - a cart object used to calculate the amount, etc. from
|
|
* @return the payment session
|
|
*/
|
|
async createSession<
|
|
TInput extends string | PaymentSessionInput = string | PaymentSessionInput
|
|
>(
|
|
providerIdOrSessionInput: TInput,
|
|
...[cart]: TInput extends string ? [Cart] : [never?]
|
|
): Promise<PaymentSession> {
|
|
return await this.atomicPhase_(async (transactionManager) => {
|
|
const providerId = isString(providerIdOrSessionInput)
|
|
? providerIdOrSessionInput
|
|
: providerIdOrSessionInput.provider_id
|
|
const data = (
|
|
isString(providerIdOrSessionInput) ? cart : providerIdOrSessionInput
|
|
) as Cart | PaymentSessionInput
|
|
|
|
const provider = this.retrieveProvider<AbstractPaymentService>(providerId)
|
|
const context = this.buildPaymentProcessorContext(data)
|
|
|
|
if (!isDefined(context.currency_code) || !isDefined(context.amount)) {
|
|
throw new MedusaError(
|
|
MedusaError.Types.INVALID_ARGUMENT,
|
|
"`currency_code` and `amount` are required to create payment session."
|
|
)
|
|
}
|
|
|
|
const paymentResponse = await provider
|
|
.withTransaction(transactionManager)
|
|
.createPayment(context)
|
|
|
|
const sessionData = paymentResponse.session_data ?? paymentResponse
|
|
|
|
await this.processUpdateRequestsData(
|
|
{
|
|
customer: { id: context.customer?.id },
|
|
},
|
|
paymentResponse
|
|
)
|
|
|
|
return await this.saveSession(providerId, {
|
|
payment_session_id: !isString(providerIdOrSessionInput)
|
|
? providerIdOrSessionInput.payment_session_id
|
|
: undefined,
|
|
cartId: context.id,
|
|
sessionData,
|
|
status: PaymentSessionStatus.PENDING,
|
|
isInitiated: true,
|
|
amount: context.amount,
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Refreshes a payment session with the given provider.
|
|
* This means, that we delete the current one and create a new.
|
|
* @param paymentSession - the payment session object to
|
|
* update
|
|
* @param sessionInput
|
|
* @return the payment session
|
|
*/
|
|
async refreshSession(
|
|
paymentSession: {
|
|
id: string
|
|
data: Record<string, unknown>
|
|
provider_id: string
|
|
},
|
|
sessionInput: PaymentSessionInput
|
|
): Promise<PaymentSession> {
|
|
return this.atomicPhase_(async (transactionManager) => {
|
|
const session = await this.retrieveSession(paymentSession.id)
|
|
const provider = this.retrieveProvider<AbstractPaymentService>(
|
|
paymentSession.provider_id
|
|
)
|
|
await provider.withTransaction(transactionManager).deletePayment(session)
|
|
|
|
const sessionRepo = transactionManager.withRepository(
|
|
this.paymentSessionRepository_
|
|
)
|
|
|
|
await sessionRepo.remove(session)
|
|
return await this.createSession(sessionInput)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Update a payment session with the given provider.
|
|
* @param paymentSession - The paymentSession to update
|
|
* @param sessionInput
|
|
* @return the payment session
|
|
*/
|
|
async updateSession(
|
|
paymentSession: {
|
|
id: string
|
|
data: Record<string, unknown>
|
|
provider_id: string
|
|
},
|
|
sessionInput: Cart | PaymentSessionInput
|
|
): Promise<PaymentSession> {
|
|
return await this.atomicPhase_(async (transactionManager) => {
|
|
const provider = this.retrieveProvider(paymentSession.provider_id)
|
|
|
|
const context = this.buildPaymentProcessorContext(sessionInput)
|
|
|
|
const paymentResponse = await provider
|
|
.withTransaction(transactionManager)
|
|
.updatePayment(paymentSession.data, context)
|
|
|
|
const sessionData = paymentResponse.session_data ?? paymentResponse
|
|
|
|
await this.processUpdateRequestsData(
|
|
{
|
|
customer: { id: context.customer?.id },
|
|
},
|
|
paymentResponse
|
|
)
|
|
|
|
return await this.saveSession(paymentSession.provider_id, {
|
|
payment_session_id: paymentSession.id,
|
|
sessionData,
|
|
isInitiated: true,
|
|
amount: context.amount,
|
|
})
|
|
})
|
|
}
|
|
|
|
async deleteSession(
|
|
paymentSession: PaymentSession
|
|
): Promise<PaymentSession | undefined> {
|
|
return await this.atomicPhase_(async (transactionManager) => {
|
|
const session = await this.retrieveSession(paymentSession.id).catch(
|
|
() => void 0
|
|
)
|
|
|
|
if (!session) {
|
|
return
|
|
}
|
|
|
|
const provider = this.retrieveProvider(paymentSession.provider_id)
|
|
await provider
|
|
.withTransaction(transactionManager)
|
|
.deletePayment(paymentSession)
|
|
|
|
const sessionRepo = transactionManager.withRepository(
|
|
this.paymentSessionRepository_
|
|
)
|
|
|
|
return await sessionRepo.remove(session)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Finds a provider given an id
|
|
* @param {string} providerId - the id of the provider to get
|
|
* @return {PaymentService} the payment provider
|
|
*/
|
|
retrieveProvider<
|
|
TProvider extends AbstractPaymentService | typeof BasePaymentService
|
|
>(
|
|
providerId: string
|
|
): TProvider extends AbstractPaymentService
|
|
? AbstractPaymentService
|
|
: typeof BasePaymentService {
|
|
try {
|
|
let provider
|
|
if (providerId === "system") {
|
|
provider = this.container_[`systemPaymentProviderService`]
|
|
} else {
|
|
provider = this.container_[`pp_${providerId}`]
|
|
}
|
|
|
|
return provider
|
|
} catch (err) {
|
|
throw new MedusaError(
|
|
MedusaError.Types.NOT_FOUND,
|
|
`Could not find a payment provider with id: ${providerId}`
|
|
)
|
|
}
|
|
}
|
|
|
|
async createPayment(data: CreatePaymentInput): Promise<Payment> {
|
|
return await this.atomicPhase_(async (transactionManager) => {
|
|
const { payment_session, currency_code, amount, provider_id } = data
|
|
const providerId = provider_id ?? payment_session.provider_id
|
|
|
|
const provider = this.retrieveProvider<AbstractPaymentService>(providerId)
|
|
const paymentData = await provider
|
|
.withTransaction(transactionManager)
|
|
.getPaymentData(payment_session)
|
|
|
|
const paymentRepo = transactionManager.withRepository(
|
|
this.paymentRepository_
|
|
)
|
|
|
|
const created = paymentRepo.create({
|
|
provider_id: providerId,
|
|
amount,
|
|
currency_code,
|
|
data: paymentData,
|
|
cart_id: data.cart_id,
|
|
})
|
|
|
|
return await paymentRepo.save(created)
|
|
})
|
|
}
|
|
|
|
async updatePayment(
|
|
paymentId: string,
|
|
data: { order_id?: string; swap_id?: string }
|
|
): Promise<Payment> {
|
|
return await this.atomicPhase_(async (transactionManager) => {
|
|
const paymentService = this.container_.paymentService
|
|
return await paymentService
|
|
.withTransaction(transactionManager)
|
|
.update(paymentId, data)
|
|
})
|
|
}
|
|
|
|
async authorizePayment(
|
|
paymentSession: PaymentSession,
|
|
context: Record<string, unknown>
|
|
): Promise<PaymentSession | undefined> {
|
|
return await this.atomicPhase_(async (transactionManager) => {
|
|
const session = await this.retrieveSession(paymentSession.id).catch(
|
|
() => void 0
|
|
)
|
|
|
|
if (!session) {
|
|
return
|
|
}
|
|
|
|
const provider = this.retrieveProvider(paymentSession.provider_id)
|
|
const { status, data } = await provider
|
|
.withTransaction(transactionManager)
|
|
.authorizePayment(session, context)
|
|
|
|
session.data = data
|
|
session.status = status
|
|
|
|
if (status === PaymentSessionStatus.AUTHORIZED) {
|
|
session.payment_authorized_at = new Date()
|
|
}
|
|
|
|
const sessionRepo = transactionManager.withRepository(
|
|
this.paymentSessionRepository_
|
|
)
|
|
return await sessionRepo.save(session)
|
|
})
|
|
}
|
|
|
|
async updateSessionData(
|
|
paymentSession: PaymentSession,
|
|
data: Record<string, unknown>
|
|
): Promise<PaymentSession> {
|
|
return await this.atomicPhase_(async (transactionManager) => {
|
|
const session = await this.retrieveSession(paymentSession.id)
|
|
|
|
const provider = this.retrieveProvider(paymentSession.provider_id)
|
|
|
|
session.data = await provider
|
|
.withTransaction(transactionManager)
|
|
.updatePaymentData(paymentSession.data, data)
|
|
session.status = paymentSession.status
|
|
|
|
const sessionRepo = transactionManager.withRepository(
|
|
this.paymentSessionRepository_
|
|
)
|
|
return await sessionRepo.save(session)
|
|
})
|
|
}
|
|
|
|
async cancelPayment(
|
|
paymentObj: Partial<Payment> & { id: string }
|
|
): Promise<Payment> {
|
|
return await this.atomicPhase_(async (transactionManager) => {
|
|
const payment = await this.retrievePayment(paymentObj.id)
|
|
const provider = this.retrieveProvider(payment.provider_id)
|
|
payment.data = await provider
|
|
.withTransaction(transactionManager)
|
|
.cancelPayment(payment)
|
|
|
|
const now = new Date()
|
|
payment.canceled_at = now.toISOString()
|
|
|
|
const paymentRepo = transactionManager.withRepository(
|
|
this.paymentRepository_
|
|
)
|
|
return await paymentRepo.save(payment)
|
|
})
|
|
}
|
|
|
|
async getStatus(payment: Payment): Promise<PaymentSessionStatus> {
|
|
const provider = this.retrieveProvider(payment.provider_id)
|
|
return await provider
|
|
.withTransaction(this.activeManager_)
|
|
.getStatus(payment.data)
|
|
}
|
|
|
|
async capturePayment(
|
|
paymentObj: Partial<Payment> & { id: string }
|
|
): Promise<Payment> {
|
|
return await this.atomicPhase_(async (transactionManager) => {
|
|
const payment = await this.retrievePayment(paymentObj.id)
|
|
const provider = this.retrieveProvider(payment.provider_id)
|
|
payment.data = await provider
|
|
.withTransaction(transactionManager)
|
|
.capturePayment(payment)
|
|
|
|
const now = new Date()
|
|
payment.captured_at = now.toISOString()
|
|
|
|
const paymentRepo = transactionManager.withRepository(
|
|
this.paymentRepository_
|
|
)
|
|
return await paymentRepo.save(payment)
|
|
})
|
|
}
|
|
|
|
async refundPayment(
|
|
payObjs: Payment[],
|
|
amount: number,
|
|
reason: string,
|
|
note?: string
|
|
): Promise<Refund> {
|
|
return await this.atomicPhase_(async (transactionManager) => {
|
|
const payments = await this.listPayments({
|
|
id: payObjs.map((p) => p.id),
|
|
})
|
|
|
|
let order_id!: string
|
|
const refundable = payments.reduce((acc, next) => {
|
|
order_id = next.order_id
|
|
if (next.captured_at) {
|
|
return (acc += next.amount - next.amount_refunded)
|
|
}
|
|
|
|
return acc
|
|
}, 0)
|
|
|
|
if (refundable < amount) {
|
|
throw new MedusaError(
|
|
MedusaError.Types.NOT_ALLOWED,
|
|
"Refund amount is greater that the refundable amount"
|
|
)
|
|
}
|
|
|
|
let balance = amount
|
|
|
|
const used: string[] = []
|
|
|
|
const paymentRepo = transactionManager.withRepository(
|
|
this.paymentRepository_
|
|
)
|
|
|
|
let paymentToRefund = payments.find(
|
|
(payment) => payment.amount - payment.amount_refunded > 0
|
|
)
|
|
|
|
while (paymentToRefund) {
|
|
const currentRefundable =
|
|
paymentToRefund.amount - paymentToRefund.amount_refunded
|
|
|
|
const refundAmount = Math.min(currentRefundable, balance)
|
|
|
|
const provider = this.retrieveProvider(paymentToRefund.provider_id)
|
|
paymentToRefund.data = await provider
|
|
.withTransaction(transactionManager)
|
|
.refundPayment(paymentToRefund, refundAmount)
|
|
|
|
paymentToRefund.amount_refunded += refundAmount
|
|
await paymentRepo.save(paymentToRefund)
|
|
|
|
balance -= refundAmount
|
|
|
|
used.push(paymentToRefund.id)
|
|
|
|
if (balance > 0) {
|
|
paymentToRefund = payments.find(
|
|
(payment) =>
|
|
payment.amount - payment.amount_refunded > 0 &&
|
|
!used.includes(payment.id)
|
|
)
|
|
} else {
|
|
paymentToRefund = undefined
|
|
}
|
|
}
|
|
|
|
const refundRepo = transactionManager.withRepository(
|
|
this.refundRepository_
|
|
)
|
|
|
|
const toCreate = {
|
|
order_id,
|
|
amount,
|
|
reason,
|
|
note,
|
|
}
|
|
|
|
const created = refundRepo.create(toCreate)
|
|
return await refundRepo.save(created)
|
|
})
|
|
}
|
|
|
|
async refundFromPayment(
|
|
payment: Payment,
|
|
amount: number,
|
|
reason: string,
|
|
note?: string
|
|
): Promise<Refund> {
|
|
return await this.atomicPhase_(async (manager) => {
|
|
const refundable = payment.amount - payment.amount_refunded
|
|
|
|
if (refundable < amount) {
|
|
throw new MedusaError(
|
|
MedusaError.Types.NOT_ALLOWED,
|
|
"Refund amount is greater that the refundable amount"
|
|
)
|
|
}
|
|
|
|
const provider = this.retrieveProvider(payment.provider_id)
|
|
payment.data = await provider
|
|
.withTransaction(manager)
|
|
.refundPayment(payment, amount)
|
|
|
|
payment.amount_refunded += amount
|
|
|
|
const paymentRepo = manager.withRepository(this.paymentRepository_)
|
|
await paymentRepo.save(payment)
|
|
|
|
const refundRepo = manager.withRepository(this.refundRepository_)
|
|
|
|
const toCreate = {
|
|
payment_id: payment.id,
|
|
amount,
|
|
reason,
|
|
note,
|
|
}
|
|
|
|
const created = refundRepo.create(toCreate)
|
|
return await refundRepo.save(created)
|
|
})
|
|
}
|
|
|
|
async retrieveRefund(
|
|
id: string,
|
|
config: FindConfig<Refund> = {}
|
|
): Promise<Refund | never> {
|
|
const refRepo = this.activeManager_.withRepository(this.refundRepository_)
|
|
const query = buildQuery({ id }, config)
|
|
const refund = await refRepo.findOne(query)
|
|
|
|
if (!refund) {
|
|
throw new MedusaError(
|
|
MedusaError.Types.NOT_FOUND,
|
|
`A refund with ${id} was not found`
|
|
)
|
|
}
|
|
|
|
return refund
|
|
}
|
|
|
|
/**
|
|
* Build the create session context for both legacy and new API
|
|
* @param cartOrData
|
|
* @protected
|
|
*/
|
|
protected buildPaymentProcessorContext(
|
|
cartOrData: Cart | PaymentSessionInput
|
|
): Cart & PaymentContext {
|
|
const cart =
|
|
"object" in cartOrData && cartOrData.object === "cart"
|
|
? cartOrData
|
|
: ((cartOrData as PaymentSessionInput).cart as Cart)
|
|
|
|
const context = {} as Cart & PaymentContext
|
|
|
|
// TODO: only to support legacy API. Once we are ready to break the API, the cartOrData will only support PaymentSessionInput
|
|
if ("object" in cartOrData && cartOrData.object === "cart") {
|
|
context.cart = {
|
|
context: cart.context,
|
|
shipping_address: cart.shipping_address,
|
|
id: cart.id,
|
|
email: cart.email,
|
|
shipping_methods: cart.shipping_methods,
|
|
}
|
|
context.amount = cart.total!
|
|
context.currency_code = cart.region?.currency_code
|
|
Object.assign(context, cart)
|
|
} else {
|
|
const data = cartOrData as PaymentSessionInput
|
|
context.cart = data.cart
|
|
context.amount = data.amount
|
|
context.currency_code = data.currency_code
|
|
context.resource_id = data.resource_id
|
|
Object.assign(context, cart)
|
|
}
|
|
|
|
return context
|
|
}
|
|
|
|
/**
|
|
* Create or update a Payment session data.
|
|
* @param providerId
|
|
* @param data
|
|
* @protected
|
|
*/
|
|
protected async saveSession(
|
|
providerId: string,
|
|
data: {
|
|
payment_session_id?: string
|
|
cartId?: string
|
|
amount?: number
|
|
sessionData: Record<string, unknown>
|
|
isSelected?: boolean
|
|
isInitiated?: boolean
|
|
status?: PaymentSessionStatus
|
|
}
|
|
): Promise<PaymentSession> {
|
|
const sessionRepo = this.activeManager_.withRepository(
|
|
this.paymentSessionRepository_
|
|
)
|
|
|
|
// Update an existing session
|
|
if (data.payment_session_id) {
|
|
const session = await this.retrieveSession(data.payment_session_id)
|
|
session.data = data.sessionData ?? session.data
|
|
session.status = data.status ?? session.status
|
|
session.amount = data.amount ?? session.amount
|
|
session.is_initiated = data.isInitiated ?? session.is_initiated
|
|
session.is_selected = data.isSelected ?? session.is_selected
|
|
return await sessionRepo.save(session)
|
|
}
|
|
|
|
// Create a new session
|
|
const toCreate: Partial<PaymentSession> = {
|
|
cart_id: data.cartId || null,
|
|
provider_id: providerId,
|
|
data: data.sessionData,
|
|
is_selected: data.isSelected,
|
|
is_initiated: data.isInitiated,
|
|
status: data.status,
|
|
amount: data.amount,
|
|
}
|
|
|
|
const created = sessionRepo.create(toCreate)
|
|
return await sessionRepo.save(created)
|
|
}
|
|
|
|
/**
|
|
* Process the collected data. Can be used every time we need to process some collected data returned by the provider
|
|
* @param data
|
|
* @param paymentResponse
|
|
* @protected
|
|
*/
|
|
protected async processUpdateRequestsData(
|
|
data: { customer?: { id?: string } } = {},
|
|
paymentResponse: PaymentSessionResponse | Record<string, unknown>
|
|
): Promise<void> {
|
|
const { update_requests } = paymentResponse as PaymentSessionResponse
|
|
|
|
if (!update_requests) {
|
|
return
|
|
}
|
|
|
|
if (update_requests.customer_metadata && data.customer?.id) {
|
|
await this.customerService_
|
|
.withTransaction(this.activeManager_)
|
|
.update(data.customer.id, {
|
|
metadata: update_requests.customer_metadata,
|
|
})
|
|
}
|
|
}
|
|
}
|