UNPKG

cbe-utils

Version:

A TypeScript utility library for CBE (Commercial Bank of Ethiopia) payment verification and transaction processing

193 lines (192 loc) 7.1 kB
"use strict"; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); const axios = require("axios"); const https = require("node:https"); const pdfTextReader = require("pdf-text-reader"); const dayjs = require("dayjs"); function _interopNamespaceDefault(e) { const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } }); if (e) { for (const k in e) { if (k !== "default") { const d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: () => e[k] }); } } } n.default = e; return Object.freeze(n); } const https__namespace = /* @__PURE__ */ _interopNamespaceDefault(https); const CBE_VERIFICATION_BASE_URL = "https://apps.cbe.com.et:100"; const TRANSACTION_REFERENCE_REGEX = /^[A-Z0-9]+$/; const TRANSACTION_URL_REGEX = /^https?:\/\/.+/; const DEFAULT_MAX_TRANSACTION_AGE_HOURS = 24; const PDF_EXTRACTION_PATTERNS = { /** Pattern to extract reference number */ REFERENCE_NUMBER: /Reference No\. \(VAT Invoice No\)\s*(.+)/, /** Pattern to extract payment date and time */ PAYMENT_DATE_TIME: /Payment Date & Time\s*(\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}:\d{2} (?:AM|PM))/, /** Pattern to extract total amount debited */ TOTAL_AMOUNT: /Total amount debited from customers account\s*([\d,.]+\s*ETB)/, /** Pattern to extract receiver information */ RECEIVER: /Receiver\s*(.+)/, /** Pattern to extract payer information */ PAYER: /Payer\s*(.+)/ }; function createHttpsAgent(rejectUnauthorized = false) { return new https__namespace.Agent({ rejectUnauthorized }); } async function downloadPdf(url, config) { const httpsAgent = createHttpsAgent(config.rejectUnauthorized); try { const response = await axios.get(url, { httpsAgent, responseType: "blob", responseEncoding: "binary", timeout: 3e4 // 30 second timeout }); return response.data; } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`Failed to download PDF: ${error.message}`); } throw new Error(`Unexpected error downloading PDF: ${error}`); } } async function extractPdfText(pdfData) { try { return await pdfTextReader.readPdfText({ data: pdfData }); } catch (error) { throw new Error(`Failed to extract text from PDF: ${error}`); } } async function extractTextFromPdfUrl(url, config) { const pdfData = await downloadPdf(url, config); return await extractPdfText(pdfData); } function validateTransactionAge(paymentDateTime, maxAgeHours = DEFAULT_MAX_TRANSACTION_AGE_HOURS) { const hoursDiff = dayjs().diff(dayjs(paymentDateTime), "hour"); if (hoursDiff > maxAgeHours) { throw new Error( `Transaction is older than ${maxAgeHours} hours (${hoursDiff} hours old), cannot verify` ); } } function extractReferenceNumber(text) { const match = text.match(PDF_EXTRACTION_PATTERNS.REFERENCE_NUMBER); return match?.[1]?.trim() || null; } function extractPaymentDateTime(text) { const match = text.match(PDF_EXTRACTION_PATTERNS.PAYMENT_DATE_TIME); if (!match?.[1]) return null; try { return new Date(match[1].trim()); } catch { return null; } } function extractTotalAmount(text) { const match = text.match(PDF_EXTRACTION_PATTERNS.TOTAL_AMOUNT); return match?.[1]?.trim() || null; } function extractReceiver(text) { const match = text.match(PDF_EXTRACTION_PATTERNS.RECEIVER); return match?.[1]?.trim() || null; } function extractPayer(text) { const match = text.match(PDF_EXTRACTION_PATTERNS.PAYER); return match?.[1]?.trim() || null; } function extractTransactionDetails(text, config) { const details = { transactionRefNumber: extractReferenceNumber(text), paymentDateTime: extractPaymentDateTime(text), totalAmountDebited: extractTotalAmount(text), receiver: extractReceiver(text), payer: extractPayer(text) }; if (!details.transactionRefNumber) { throw new Error("Transaction reference number not found in the PDF"); } if (!details.paymentDateTime) { throw new Error("Payment date and time not found in the PDF"); } const maxAge = config.maxTransactionAgeHours ?? DEFAULT_MAX_TRANSACTION_AGE_HOURS; validateTransactionAge(details.paymentDateTime, maxAge); return details; } function validateInput(input) { if (!input || typeof input !== "string") { throw new Error("Input must be a non-empty string"); } const isValidRef = TRANSACTION_REFERENCE_REGEX.test(input); const isValidUrl = TRANSACTION_URL_REGEX.test(input); if (!isValidRef && !isValidUrl) { throw new Error("Invalid transaction reference number or URL format"); } } function constructPdfUrl(input, cbeAccountNumber) { if (TRANSACTION_URL_REGEX.test(input)) { return input.slice(0, -8) + cbeAccountNumber.slice(-8); } if (TRANSACTION_REFERENCE_REGEX.test(input)) { return `${CBE_VERIFICATION_BASE_URL}/?id=${input}${cbeAccountNumber.slice(-8)}`; } throw new Error("Unable to construct PDF URL from input"); } function createDefaultConfig(cbeAccountNumber, overrides = {}) { return { cbeAccountNumber, maxTransactionAgeHours: DEFAULT_MAX_TRANSACTION_AGE_HOURS, rejectUnauthorized: false, // Default to false for CBE compatibility ...overrides }; } async function verifyDirectDeposit(transactionRefNumberOrUrl, config) { validateInput(transactionRefNumberOrUrl); if (!config.cbeAccountNumber) { throw new Error("CBE account number is required for verification"); } try { const pdfUrl = constructPdfUrl(transactionRefNumberOrUrl, config.cbeAccountNumber); const pdfText = await extractTextFromPdfUrl(pdfUrl, config); const transactionDetails = extractTransactionDetails(pdfText, config); return transactionDetails; } catch (error) { if (error instanceof Error) { throw error; } throw new Error(`Verification failed: ${error}`); } } async function verifyPayment(transactionRefNumberOrUrl, cbeAccountNumber, options = {}) { const config = createDefaultConfig(cbeAccountNumber, options); return verifyDirectDeposit(transactionRefNumberOrUrl, config); } function isValidCbeAccountNumber(accountNumber) { return typeof accountNumber === "string" && accountNumber.length >= 8 && /^\d+$/.test(accountNumber); } const index = { verifyDirectDeposit, verifyPayment, isValidCbeAccountNumber }; exports.CBE_VERIFICATION_BASE_URL = CBE_VERIFICATION_BASE_URL; exports.DEFAULT_MAX_TRANSACTION_AGE_HOURS = DEFAULT_MAX_TRANSACTION_AGE_HOURS; exports.TRANSACTION_REFERENCE_REGEX = TRANSACTION_REFERENCE_REGEX; exports.TRANSACTION_URL_REGEX = TRANSACTION_URL_REGEX; exports.default = index; exports.downloadPdf = downloadPdf; exports.extractPdfText = extractPdfText; exports.extractTextFromPdfUrl = extractTextFromPdfUrl; exports.extractTransactionDetails = extractTransactionDetails; exports.isValidCbeAccountNumber = isValidCbeAccountNumber; exports.verifyDirectDeposit = verifyDirectDeposit; exports.verifyPayment = verifyPayment; //# sourceMappingURL=index.cjs.map