UNPKG

dinger-merchant-pay-api

Version:
297 lines (256 loc) 12.4 kB
import cryptolib from 'aes-ecb'; import NodeRSA from 'node-rsa'; const baseURL = 'https://api.dinger.asia'; const portalUrl = 'https://portal.dinger.asia/gateway'; const creditUrl = 'https://creditcard-portal.dinger.asia'; const uatBaseURL = 'https://staging.dinger.asia/payment-gateway-uat'; const uatPortalUrl = 'https://staging.dinger.asia/gateway'; const uatCreditUrl = 'https://staging-creditcard-portal.dinger.asia/gateway'; export interface PayOptions { providerName: string; methodName: string; totalAmount: number; orderId: string; customerPhone: string; customerName: string; description?: string; customerAddress?: string; email?: string; state?: string; country?: string; postalCode?: string; billAddress?: string; billCity?: string; items: string | {name: string; amount: number; quantity: number}[]; projectName?: string; } export class DingerPay { private projectName: string; private merchantName: string; private apiKey: string; private pubKey: string; private cbkKey: string; private environment: "PRODUCTION" | "UAT"; private appBaseUrl: string; private appPortalUrl: string; private appCreditUrl: string; constructor( projectName: string, merchantName: string, apiKey: string, pubKey: string, cbkKey: string, environment: "PRODUCTION" | "UAT" ) { this.projectName = projectName; this.merchantName = merchantName; this.apiKey = apiKey; this.pubKey = pubKey; this.cbkKey = cbkKey; this.environment = environment; if (this.environment === "PRODUCTION") { this.appBaseUrl = baseURL; this.appPortalUrl = portalUrl; this.appCreditUrl = creditUrl; } else { this.appBaseUrl = uatBaseURL; this.appPortalUrl = uatPortalUrl; this.appCreditUrl = uatCreditUrl; } } public queryBearerToken = async (): Promise<any> => { const url = new URL(`${this.appBaseUrl}/api/token`); url.search = new URLSearchParams({ projectName: this.projectName, merchantName: this.merchantName, apiKey: this.apiKey }).toString(); const response = await fetch(url.toString(), { method: 'GET' }); return await response.json(); } public pay = async (opts: PayOptions): Promise<any> => { const payload = JSON.stringify(opts); const publicKey = new NodeRSA(); publicKey.importKey(this.pubKey, 'pkcs8-public'); publicKey.setOptions({encryptionScheme: 'pkcs1'}); const token = await this.queryBearerToken(); const body = new URLSearchParams({ payload: publicKey.encrypt(payload, 'base64') }); const response = await fetch(`${this.appBaseUrl}/api/pay`, { method: 'POST', headers: { 'Authorization': `Bearer ${token.response.paymentToken}`, 'Content-Type': 'application/x-www-form-urlencoded' }, body: body.toString() }); return await response.json(); } public queryCheckPerson = async (phoneNumber: string, appName: string): Promise<any> => { const url = new URL(`${this.appBaseUrl}/checkPhone`); url.search = new URLSearchParams({ phoneNumber, appName }).toString(); const response = await fetch(url.toString(), { method: 'GET' }); return await response.json(); } public queryCountryCode = async (): Promise<any> => { const response = await fetch(`${this.appBaseUrl}/api/countryCodeListEnquiry`, { method: 'GET' }); return await response.json(); } public verifyCb = async (opts: {paymentResult: string}): Promise<any> => { return JSON.parse(cryptolib.decrypt(this.cbkKey, opts.paymentResult)); } public queryAllNameSpace = async (): Promise<any[]> => { return [ {providerName: "KBZ Pay", methodName: "QR", flow: "QR", logo: ""}, {providerName: "KBZ Pay", methodName: "PWA", flow: "REDIRECT", logo: ""}, {providerName: "AYA Pay", methodName: "QR", flow: "QR", logo: ""}, {providerName: "AYA Pay", methodName: "PIN", flow: "NOTIFICATION", logo: ""}, {providerName: "Citizens Pay", methodName: "PIN", flow: "REDIRECT", logo: ""}, {providerName: "Wave Pay", methodName: "PIN", flow: "REDIRECT", logo: ""}, {providerName: "MPU", methodName: "OTP", flow: "REDIRECT", logo: ""}, {providerName: "Mytel", methodName: "PIN", flow: "REDIRECT", logo: ""}, {providerName: "Sai Sai Pay", methodName: "PIN", flow: "NOTIFICATION", logo: ""}, {providerName: "Onepay", methodName: "PIN", flow: "NOTIFICATION", logo: ""}, {providerName: "MPitesan", methodName: "PIN", flow: "REDIRECT", logo: ""}, {providerName: "KBZ Direct Pay", methodName: "PWA", flow: "REDIRECT", logo: ""}, {providerName: "Visa", methodName: "OTP", flow: "REDIRECT", logo: ""}, {providerName: "Master", methodName: "OTP", flow: "REDIRECT", logo: ""}, {providerName: "MPU", methodName: "OTP", flow: "REDIRECT", logo: ""}, {providerName: "CB Pay", methodName: "QR", flow: "REDIRECT", logo: ""}, {providerName: "MAB Bank", methodName: "OTP", flow: "REDIRECT", logo: ""}, {providerName: "MPT Pay", methodName: "PIN", flow: "REDIRECT", logo: ""}, {providerName: "OK Dollar", methodName: "PIN", flow: "REDIRECT", logo: ""}, {providerName: "UAB Pay", methodName: "PIN", flow: "NOTIFICATION", logo: ""}, {providerName: "TrueMoney", methodName: "PIN", flow: "NOTIFICATION", logo: ""}, ]; } public handleVendorResponse = async (opts: PayOptions, payResponse: any): Promise<any> => { const data = payResponse.response; let flowOperation = "REDIRECT"; let redirectLink: string | null = `${this.appPortalUrl}/redirect?transactionNo=${data.transactionNum}&formToken=${data.formToken}&merchantOrderId=${data.merchOrderId}`; let qrCode = ""; if (opts.providerName === "MPU") { redirectLink = `${this.appPortalUrl}/mpu?transactionNo=${data.transactionNum}&formToken=${data.formToken}&merchantOrderId=${data.merchOrderId}`; } if (opts.providerName === "MPitesan") { redirectLink = `${this.appPortalUrl}/mpitesan?transactionNo=${data.transactionNum}&formToken=${data.formToken}&merchantOrderId=${data.merchOrderId}`; } if (opts.providerName === "CB Pay") { redirectLink = `${this.appPortalUrl}/cbpay?transactionNo=${data.transactionNum}&formToken=${data.formToken}&merchantOrderId=${data.merchOrderId}`; } if ( opts.providerName === "Visa" || opts.providerName === "Master" || opts.providerName === "JCB" ) { redirectLink = `${this.appCreditUrl}/?transactionNo=${data.transactionNum}&formToken=${data.formToken}&merchantOrderId=${data.merchOrderId}`; } if (opts.providerName === "KBZ Pay" && opts.methodName === "QR") { qrCode = data.qrCode; flowOperation = "QR"; redirectLink = null; } if (opts.providerName === "AYA Pay" && opts.methodName === "QR") { qrCode = data.qrCode; flowOperation = "QR"; redirectLink = null; } if (opts.providerName === "AYA Pay" && opts.methodName === "PIN") { flowOperation = "NOTIFICATION"; redirectLink = null; } if (opts.providerName === "Onepay") { flowOperation = "NOTIFICATION"; redirectLink = null; } if (opts.providerName === "Sai Sai Pay") { flowOperation = "NOTIFICATION"; redirectLink = null; } if (opts.providerName === "UAB Pay") { flowOperation = "NOTIFICATION"; redirectLink = null; } return { flowOperation: flowOperation, redirectLink: redirectLink, qrCode: qrCode }; } public orderTransactionFee = async (amount: number, vender: string, digital: string = 'no'): Promise<number> => { let tx = 0; switch (vender) { case "KBZ Direct Pay": (digital === 'yes') ? tx = amount * 0.15 : tx = amount * 0.019; break; case "KBZ Pay": (digital === 'yes') ? tx = amount * 0.15 : tx = amount * 0.019; break; case "Citizens Pay": tx = amount * 0.019; break; case "WAVE Pay": tx = amount * 0.034; break; case "TrueMoney": tx = (amount * 0.004) + 200; break; case "Mytel Pay": tx = amount * 0.02; break; case "AYA Pay": tx = amount * 0.007; break; case "MPU": tx = (amount * 0.008) + 200; break; case "UAB Pay": tx = amount * 0.009; break; case "Sai Sai Pay": tx = amount * 0.009; break; case "MPitesan": tx = amount * 0.019; break; case "Onepay": tx = amount * 0.016; break; case "Visa": tx = amount * 0.039; break; case "Master": tx = amount * 0.039; break; case "JCB": tx = amount * 0.039; break; case "CB Pay": tx = amount * 0.015; break; case "MAB Bank": (amount < 200000) ? tx = 1200 : tx = amount * 0.01; break; case "MPT Pay": tx = amount * 0.015; break; case "OK Dollar": tx = amount * 0.004; break; } return tx; } public validatePayload = async (opts: PayOptions): Promise<{pass: boolean; message: string}> => { let response = {pass: true, message: ""}; if (!opts.providerName) {response.pass = false; response.message = "[providerName] is required";} if (!opts.methodName) {response.pass = false; response.message = "[methodName] is required";} if (!opts.totalAmount) {response.pass = false; response.message = "[totalAmount] is required";} if (!opts.orderId) {response.pass = false; response.message = "[orderId] is required";} if (!opts.customerPhone) {response.pass = false; response.message = "[customerPhone] is required";} if (!opts.customerName) {response.pass = false; response.message = "[customerName] is required";} if (!opts.items) {response.pass = false; response.message = "[items] is required";} let totalAmount = 0; const parsedItems = typeof opts.items === 'string' ? JSON.parse(opts.items) : opts.items; for (let item of parsedItems) { totalAmount += item.amount * item.quantity; } if (opts.totalAmount != totalAmount) { response.pass = false; response.message = "[totalAmount] not matched"; } if ( opts.providerName === "Visa" || opts.providerName === "Master" || opts.providerName === "JCB" ) { if (!opts.email) {response.pass = false; response.message = "[email] is required for Visa, Master, JCB";} if (!opts.state) {response.pass = false; response.message = "[state] is required for Visa, Master, JCB";} if (!opts.country) {response.pass = false; response.message = "[country] is required for Visa, Master, JCB";} if (!opts.postalCode) {response.pass = false; response.message = "[postalCode] is required for Visa, Master, JCB";} if (!opts.billAddress) {response.pass = false; response.message = "[billAddress] is required for Visa, Master, JCB";} if (!opts.billCity) {response.pass = false; response.message = "[billCity] is required for Visa, Master, JCB";} } if ( opts.providerName === "Sai Sai Pay" || opts.providerName === "UAB Pay" ) { const projectName = opts.projectName || this.projectName; let personResponse = await this.queryCheckPerson(opts.customerPhone, projectName); if (personResponse.response.Code !== "000") { response.pass = false; response.message = "[user] is not valid"; } } return response; } }