Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { AbstractPaymentProvider, MedusaError } from "@medusajs/framework/utils"
- import { Logger } from "@medusajs/medusa"
- import {
- SquareClient as Client,
- SquareEnvironment as Environment,
- Square
- } from "square"
- import {
- AuthorizePaymentInput,
- AuthorizePaymentOutput,
- CancelPaymentInput,
- CancelPaymentOutput,
- CapturePaymentInput,
- CapturePaymentOutput,
- DeletePaymentInput,
- DeletePaymentOutput,
- GetPaymentStatusInput,
- GetPaymentStatusOutput,
- InitiatePaymentInput,
- InitiatePaymentOutput,
- PaymentSessionStatus,
- ProviderWebhookPayload,
- RefundPaymentInput,
- RefundPaymentOutput,
- RetrievePaymentInput,
- RetrievePaymentOutput,
- UpdatePaymentInput,
- UpdatePaymentOutput,
- WebhookActionResult
- } from "@medusajs/framework/types"
- export type Options = {
- access_token: string
- application_id?: string
- location_id?: string
- environment?: 'sandbox' | 'production'
- webhook_secret?: string
- capture_method?: 'automatic' | 'manual'
- }
- type InjectedDependencies = {
- logger: Logger
- }
- export class SquarePaymentProvider extends AbstractPaymentProvider<Options> {
- static identifier = "square-payment-provider"
- protected logger_: Logger
- protected options_: Options
- protected squareClient_: Client
- constructor(container: InjectedDependencies, options: Options) {
- super(container, options)
- this.logger_ = container.logger
- this.options_ = options
- this.squareClient_ = new Client({
- token: options.access_token,
- environment: options.environment === 'production' ? Environment.Production : Environment.Sandbox,
- })
- }
- static validateOptions(options: Options) {
- if (!options.access_token) {
- throw new MedusaError(
- MedusaError.Types.INVALID_DATA,
- "Square access token is required in the provider's options."
- )
- }
- }
- async getPaymentStatus(input: GetPaymentStatusInput): Promise<GetPaymentStatusOutput> {
- const paymentId = input.data?.id as string
- try {
- const { payment } = await this.squareClient_.payments.get({
- paymentId
- })
- if (payment) {
- return {
- status: this.mapSquareStatusToMedusa(payment.status || 'PENDING'),
- }
- } else {
- return {
- status: this.mapSquareStatusToMedusa('PENDING')
- }
- }
- } catch (error) {
- this.logger_.error(`Failed to get Square payment status: ${error}`)
- return {
- status: this.mapSquareStatusToMedusa('PENDING')
- }
- }
- }
- async initiatePayment(input: InitiatePaymentInput): Promise<InitiatePaymentOutput> {
- try {
- const { context = {}, data = {}, amount, currency_code } = input
- const paymentIntent = {
- sourceId: data.source_id || data.nonce,
- idempotencyKey: context.idempotency_key || `auth_${Date.now()}`,
- amountMoney: {
- amount: BigInt(amount.toString()),
- currency: currency_code.toUpperCase() as Square.Currency
- },
- orderId: data?.orderId,
- locationId: data?.locationId || this.options_.location_id,
- customerId: context?.customer?.id,
- buyerEmailAddress: context?.customer?.email,
- buyerPhoneNumber: context?.customer?.phone,
- referenceId: context?.idempotency_key,
- captureMethod: this.options_.capture_method || 'automatic',
- createdAt: new Date(),
- status: 'PENDING'
- } as Square.CreatePaymentRequest
- this.logger_.info(`Square payment initiated: ${paymentIntent.idempotencyKey} for amount: ${amount} ${currency_code}`)
- const { payment } = await this.squareClient_.payments.create(paymentIntent)
- if (!payment) {
- throw new MedusaError(
- MedusaError.Types.INVALID_DATA,
- "Square payment initiation failed"
- )
- }
- return {
- id: payment.id!,
- data: this.mapSquarePaymentToMedusa(payment, paymentIntent.idempotencyKey),
- }
- } catch (error) {
- this.logger_.error(`Square payment initiation failed: ${error}`)
- throw error
- }
- }
- async authorizePayment(
- input: AuthorizePaymentInput
- ): Promise<AuthorizePaymentOutput> {
- try {
- if (!input.data || !input.data.id || !input.data.idempotencyKey) {
- throw new MedusaError(
- MedusaError.Types.INVALID_DATA,
- "Payment data with valid id and idempotencyKey is required for authorization"
- )
- }
- const { payment } = await this.squareClient_.payments.update({
- paymentId: input.data.id as string,
- idempotencyKey: input.data.idempotencyKey as string,
- payment: {
- status: 'APPROVED'
- }
- })
- return {
- status: this.mapSquareStatusToMedusa(payment?.status || 'PENDING'),
- data: this.mapSquarePaymentToMedusa(payment!, input.data.idempotencyKey as string),
- }
- } catch (error) {
- this.logger_.error(`Square payment authorization failed: ${error}`)
- throw error
- }
- }
- async capturePayment(input: CapturePaymentInput): Promise<CapturePaymentOutput> {
- try {
- if (!input.data || !input.data.id) {
- throw new MedusaError(
- MedusaError.Types.INVALID_DATA,
- "Payment data with valid id is required for capture"
- )
- }
- const paymentId = input.data.id as string
- this.logger_.info(`Capturing Square payment: ${paymentId}`)
- const { payment } = await this.squareClient_.payments.complete({
- paymentId: paymentId,
- })
- if (payment) {
- return {
- data: this.mapSquarePaymentToMedusa(payment, input.data.idempotencyKey as string),
- }
- } else {
- throw new Error("Square payment capture failed")
- }
- } catch (error) {
- this.logger_.error(`Square payment capture failed: ${error}`)
- throw error
- }
- }
- async cancelPayment(input: CancelPaymentInput): Promise<CancelPaymentOutput> {
- try {
- if (!input.data || !input.data.id) {
- throw new MedusaError(
- MedusaError.Types.INVALID_DATA,
- "Payment data with valid id is required for cancellation"
- )
- }
- const paymentId = input.data.id as string
- this.logger_.info(`Canceling Square payment: ${paymentId}`)
- const { payment } = await this.squareClient_.payments.cancel({
- paymentId
- })
- if (payment) {
- return {
- data: this.mapSquarePaymentToMedusa(payment, input.data.idempotencyKey as string),
- }
- } else {
- throw new Error("Square payment cancellation failed")
- }
- } catch (error) {
- this.logger_.error(`Square payment cancellation failed: ${error}`)
- throw error
- }
- }
- async deletePayment(input: DeletePaymentInput): Promise<DeletePaymentOutput> {
- // Square doesn't support deleting payments, only canceling
- return this.cancelPayment(input)
- }
- async retrievePayment(input: RetrievePaymentInput): Promise<RetrievePaymentOutput> {
- try {
- if (!input.data || !input.data.id) {
- throw new MedusaError(
- MedusaError.Types.INVALID_DATA,
- "Payment data with valid id is required for retrieval"
- )
- }
- const paymentId = input.data.id as string
- const { payment } = await this.squareClient_.payments.get({
- paymentId
- })
- if (payment) {
- return {
- data: this.mapSquarePaymentToMedusa(payment, input.data.idempotencyKey as string)
- }
- } else {
- throw new Error("Square payment not found")
- }
- } catch (error) {
- this.logger_.error(`Square payment retrieval failed: ${error}`)
- throw error
- }
- }
- async updatePayment(input: UpdatePaymentInput): Promise<UpdatePaymentOutput> {
- try {
- if (!input.data || !input.data.id || !input.data.idempotencyKey) {
- throw new MedusaError(
- MedusaError.Types.INVALID_DATA,
- "Payment data with valid id and idempotencyKey is required for update"
- )
- }
- const paymentId = input.data.id as string
- const { payment } = await this.squareClient_.payments.update({
- paymentId,
- idempotencyKey: input.data.idempotencyKey as string,
- payment: input.data
- })
- if (payment) {
- return {
- data: this.mapSquarePaymentToMedusa(payment, input.data.idempotencyKey as string),
- }
- } else {
- throw new Error("Square payment update failed")
- }
- } catch (error) {
- this.logger_.error(`Square payment update failed: ${error}`)
- throw error
- }
- }
- async refundPayment(
- input: RefundPaymentInput
- ): Promise<RefundPaymentOutput> {
- try {
- if (!input.data || !input.data.id || !input.data.idempotencyKey) {
- throw new Error("Square payment ID is required for refund")
- }
- const paymentId = input.data.id as string
- this.logger_.info(`Creating Square refund for payment: ${paymentId}`)
- const { refund } = await this.squareClient_.refunds.refundPayment({
- idempotencyKey: input.data.idempotencyKey as string,
- paymentId: paymentId,
- amountMoney: {
- amount: BigInt(input.amount.toString()),
- currency: input.data.currency as Square.Currency
- },
- reason: 'Refund requested'
- })
- if (refund) {
- return {
- data: {
- id: refund.id,
- status: refund.status,
- locationId: refund.locationId,
- unlinked: refund.unlinked,
- amountMoney: refund.amountMoney,
- appFeeMoney: refund.appFeeMoney,
- destinationType: refund.destinationType,
- destinationDetails: refund.destinationDetails,
- processingFee: refund.processingFee,
- paymentId: refund.paymentId,
- orderId: refund.orderId,
- reason: refund.reason,
- createdAt: refund.createdAt,
- updatedAt: refund.updatedAt
- }
- }
- } else {
- throw new Error("Square refund creation failed")
- }
- } catch (error) {
- this.logger_.error(`Square refund failed: ${error}`)
- throw error
- }
- }
- async getWebhookActionAndData(data: ProviderWebhookPayload["payload"]): Promise<WebhookActionResult> {
- this.logger_.info(`Received Square webhook: ${JSON.stringify(data)}`)
- throw new Error("Method not implemented.")
- }
- private mapSquareStatusToMedusa(squareStatus: string): PaymentSessionStatus {
- const statusMap = {
- 'APPROVED': 'authorized',
- 'COMPLETED': 'captured',
- 'CANCELED': 'canceled',
- 'FAILED': 'error',
- 'PENDING': 'pending',
- }
- return statusMap[squareStatus] || 'pending'
- }
- private mapSquarePaymentToMedusa(payment: Square.Payment, idempotencyKey?: string) {
- return {
- id: payment.id,
- idempotencyKey: idempotencyKey || (payment as any).idempotencyKey,
- amount: Number(payment.amountMoney?.amount || 0),
- currency: payment.amountMoney?.currency,
- status: this.mapSquareStatusToMedusa(payment.status || 'PENDING'),
- refundedMoney: payment.refundedMoney,
- billingAddress: payment.billingAddress,
- shippingAddress: payment.shippingAddress,
- buyerEmailAddress: payment.buyerEmailAddress,
- customerId: payment.customerId,
- referenceId: payment.referenceId,
- orderId: payment.orderId,
- locationId: payment.locationId,
- createdAt: payment.createdAt,
- updatedAt: payment.updatedAt,
- }
- }
- }
- export default SquarePaymentProvider
Advertisement
Add Comment
Please, Sign In to add comment