UNPKG

@tecafrik/africa-payment-sdk

Version:

A single SDK to integrate all african payment providers seamlessly

180 lines (163 loc) 6 kB
import { MobileMoneyCheckoutOptions, CheckoutResult, PaymentProvider, RefundOptions, RefundResult, CreditCardCheckoutOptions, RedirectCheckoutOptions, TransactionStatus, PaymentMethod, HandleWebhookOptions, Currency, MobileMoneyPayoutOptions, PayoutResult, } from "../payment-provider.interface"; import EventEmitter2 from "eventemitter2"; import { PaymentEventType, PaymentFailedEvent, PaymentInitiatedEvent, PaymentSuccessfulEvent, } from "../payment-events"; class BogusPaymentProvider implements PaymentProvider { private eventEmitter?: EventEmitter2; constructor(private config: BogusPaymentProviderConfig) {} useEventEmitter(eventEmitter: EventEmitter2) { this.eventEmitter = eventEmitter; } async checkout( options: | MobileMoneyCheckoutOptions | CreditCardCheckoutOptions | RedirectCheckoutOptions, isFailure: boolean ): Promise<CheckoutResult> { if (this.config.instantEvents) { this.eventEmitter?.emit(PaymentEventType.PAYMENT_INITIATED, { type: PaymentEventType.PAYMENT_INITIATED, transactionAmount: options.amount, transactionCurrency: options.currency, transactionId: options.transactionId, transactionReference: `${options.paymentMethod.toLowerCase()}-transaction-reference`, paymentMethod: PaymentMethod.WAVE, metadata: options.metadata, paymentProvider: BogusPaymentProvider.name, } as PaymentInitiatedEvent); if (isFailure) { this.eventEmitter?.emit(PaymentEventType.PAYMENT_FAILED, { type: PaymentEventType.PAYMENT_FAILED, transactionAmount: options.amount, transactionCurrency: options.currency, transactionId: options.transactionId, transactionReference: `${options.paymentMethod.toLowerCase()}-transaction-reference`, paymentMethod: PaymentMethod.WAVE, metadata: options.metadata, reason: "Payment failed", paymentProvider: BogusPaymentProvider.name, } as PaymentFailedEvent); } else { this.eventEmitter?.emit(PaymentEventType.PAYMENT_SUCCESSFUL, { type: PaymentEventType.PAYMENT_SUCCESSFUL, transactionAmount: options.amount, transactionCurrency: options.currency, transactionId: options.transactionId, transactionReference: `${options.paymentMethod.toLowerCase()}-transaction-reference`, paymentMethod: PaymentMethod.WAVE, metadata: options.metadata, paymentProvider: BogusPaymentProvider.name, } as PaymentSuccessfulEvent); } } return { transactionAmount: options.amount, transactionCurrency: options.currency, transactionId: options.transactionId, transactionReference: `${options.paymentMethod.toLowerCase()}-transaction-reference`, transactionStatus: TransactionStatus.PENDING, redirectUrl: isFailure ? options.failureRedirectUrl : options.successRedirectUrl, }; } async checkoutMobileMoney( options: MobileMoneyCheckoutOptions ): Promise<CheckoutResult> { let isFailure = false; if (options.paymentMethod === PaymentMethod.WAVE) { isFailure = options.customer.phoneNumber.endsWith("13"); } else if (options.paymentMethod === PaymentMethod.ORANGE_MONEY) { isFailure = options.authorizationCode?.endsWith("13") || false; } return this.checkout(options, isFailure); } async checkoutCreditCard( options: CreditCardCheckoutOptions ): Promise<CheckoutResult> { const isFailure = options.cardNumber?.endsWith("13") || false; return this.checkout(options, isFailure); } async checkoutRedirect( options: RedirectCheckoutOptions ): Promise<CheckoutResult> { const isFailure = options.customer.email?.endsWith("failure.com") ?? false; return this.checkout(options, isFailure); } async refund(options: RefundOptions): Promise<RefundResult> { console.debug("Refunding transaction", options.transactionId, options); return { transactionAmount: options.refundedAmount || 0, transactionCurrency: Currency.XOF, transactionId: options.transactionId, transactionReference: `refunded-transaction-reference`, transactionStatus: TransactionStatus.PENDING, }; } async handleWebhook(rawBody: Buffer | string, options: HandleWebhookOptions) { const body = JSON.parse( rawBody.toString() ) as BogusPaymentProviderWebhookBody; const isFailure = body.success === false; const eventType = isFailure ? PaymentEventType.PAYMENT_FAILED : PaymentEventType.PAYMENT_SUCCESSFUL; const event = { type: eventType, transactionAmount: body.amount, transactionCurrency: body.currency, transactionId: body.transactionId, transactionReference: body.transactionReference, paymentMethod: body.paymentMethod, metadata: body.metadata, paymentProvider: BogusPaymentProvider.name, } as PaymentSuccessfulEvent | PaymentFailedEvent; this.eventEmitter?.emit(eventType, event); return event; } payoutMobileMoney(options: MobileMoneyPayoutOptions): Promise<PayoutResult> { console.debug("Paying out mobile money", options); return Promise.resolve({ transactionAmount: options.amount, transactionCurrency: options.currency, transactionId: options.transactionId, transactionReference: `payout-transaction-reference`, transactionStatus: TransactionStatus.SUCCESS, }); } } type BogusPaymentProviderConfig = { /** * Whether to emit events instantly or wait for the webhook to be called */ instantEvents: boolean; }; export type BogusPaymentProviderWebhookBody = { success: boolean; amount: number; transactionId: string; transactionReference: string; paymentMethod: PaymentMethod; currency: Currency; metadata?: Record<string, unknown>; }; export default BogusPaymentProvider;