zibal_zibal.ts

import axios from 'axios'
import { ZibalUrls } from './enums/urls.enum'
import { TransactionCreateInputZibal, TransactionVerifyInputZibal } from './interfaces/requests.interface'
import { TransactionCreateResponseZibal, TransactionVerifyResponseZibal } from './interfaces/response.interface'
import { zibalMessages } from './enums/message.enum'

/**
 * Class to interact with the Zibal payment gateway.
 *
 * @class ZibalDriver
 */
export class ZibalDriver {
  private merchant: string | null = null

  setToken(merchant: string): this {
    if (!merchant) {
      throw new Error('invalid parameters')
    }

    this.merchant = merchant
    return this
  }

  /**
   * Create a payment request to Zibal.
   *
   * @param {TransactionCreateInputZibal} data - Input data for creating the transaction.
   * @param {boolean} [sandbox=false] - Flag to determine whether to use the sandbox environment.
   * @returns {Promise<TransactionCreateResponseZibal>} Response from the Zibal API for creating a transaction.
   */
  async request(data: TransactionCreateInputZibal, sandbox: boolean = false): Promise<TransactionCreateResponseZibal> {
    try {
      if (!sandbox) {
        if (!this.merchant || !data.merchant) {
          throw new Error(`merchant is required for this request`)
        }
      }

      if (!data.amount || !data.callbackUrl) {
        throw new Error('invalid parameters')
      }

      const requestUrl = ZibalUrls.REQUEST

      const { data: dataAxios } = await axios.post(requestUrl, {
        ...data,
        merchant: sandbox ? 'zibal' : this.merchant || data.merchant
      })

      dataAxios.isError = dataAxios.result !== 100
      if (dataAxios.isError) {
        return {
          data: null,
          error: {
            message: zibalMessages[dataAxios.result] || dataAxios.message,
            code: 0
          },
          isError: true
        }
      }

      return {
        isError: false,
        error: null,
        data: {
          trackId: dataAxios.trackId,
          url: `https://gateway.zibal.ir/start/${dataAxios.trackId}`
        }
      }
    } catch (error: any) {
      const message = error.message || 'An error occurred while processing the request'
      return {
        error: {
          message,
          code: error.code || 500
        },
        isError: true,
        data: null
      }
    }
  }

  /**
   * Verify a payment transaction with Zibal.
   *
   * @param {TransactionVerifyInputZibal} data - Input data for verifying the transaction.
   * @param {boolean} [sandbox=false] - Flag to determine whether to use the sandbox environment.
   * @returns {Promise<TransactionVerifyResponseZibal>} Response from the Zibal API for verifying a transaction.
   */
  async verify(data: TransactionVerifyInputZibal, sandbox: boolean): Promise<TransactionVerifyResponseZibal> {
    try {
      if (!sandbox) {
        if (!this.merchant || !data.merchant) {
          throw new Error(`merchant is required for this request`)
        }
      }

      if (!data.trackId) {
        throw new Error(`trackId is required for this request`)
      }

      const requestUrl = ZibalUrls.VERIFY

      const { data: dataAxios } = await axios.post(requestUrl, {
        ...data,
        merchant: sandbox ? 'zibal' : this.merchant || data.merchant
      })

      dataAxios.isError = dataAxios.result !== 100

      if (dataAxios.isError) {
        return {
          data: null,
          error: {
            message: zibalMessages[dataAxios.result] || dataAxios.message,
            code: 0
          },
          isError: true
        }
      }

      return {
        data: {
          amount: dataAxios.amount,
          cartNumber: dataAxios.cardNumber,
          description: dataAxios.description,
          message: dataAxios.message,
          multiplexingInfos: dataAxios.multiplexingInfos,
          orderId: dataAxios.orderId,
          paidAt: dataAxios.paidAt,
          refNumber: dataAxios.refNumber,
          status: dataAxios.status
        },
        isError: false,
        error: null
      }
    } catch (error: any) {
      const message = error.message || 'An error occurred while processing the request'
      return {
        error: {
          message,
          code: error.code || 500
        },
        isError: true,
        data: null
      }
    }
  }
}