@tecafrik/africa-payment-sdk
Version:
A single SDK to integrate all african payment providers seamlessly
280 lines • 14.6 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TaarihTransactionStatus = void 0;
const libphonenumber_js_1 = require("libphonenumber-js");
const payment_provider_interface_1 = require("../payment-provider.interface");
const apisauce_1 = require("apisauce");
const payment_error_1 = require("../payment-error");
const lodash_1 = require("lodash");
const payment_events_1 = require("../payment-events");
var TaarihTransactionStatus;
(function (TaarihTransactionStatus) {
TaarihTransactionStatus["PENDING"] = "PENDING";
TaarihTransactionStatus["COMPLETED"] = "COMPLETED";
TaarihTransactionStatus["FAILED"] = "FAILED";
})(TaarihTransactionStatus || (exports.TaarihTransactionStatus = TaarihTransactionStatus = {}));
var TaarihCreditCardPaymentProcessor;
(function (TaarihCreditCardPaymentProcessor) {
TaarihCreditCardPaymentProcessor["CINETPAY"] = "CINETPAY";
TaarihCreditCardPaymentProcessor["STRIPE"] = "STRIPE";
})(TaarihCreditCardPaymentProcessor || (TaarihCreditCardPaymentProcessor = {}));
class TaarihPaymentProvider {
constructor(config) {
this.config = config;
this.api = (0, apisauce_1.create)({
baseURL: config.mode === "test"
? "https://api-dev.taarih.com/api"
: "https://api.taarih.com/api",
headers: {
"Content-Type": "application/json",
},
});
this.api.addResponseTransform((response) => {
if (!response.ok) {
const defaultErrorMessage = "Taarih error: " +
response.problem +
". Status: " +
response.status +
". Data: " +
JSON.stringify(response.data);
console.error(response);
throw new payment_error_1.PaymentError(response.data && (0, lodash_1.isObject)(response.data)
? "message" in response.data
? String(response.data.message)
: "response_text" in response.data
? String(response.data.response_text)
: defaultErrorMessage
: defaultErrorMessage);
}
});
}
useEventEmitter(eventEmitter) {
this.eventEmitter = eventEmitter;
}
getTaarihPaymentMethod(paymentMethod, processor) {
switch (paymentMethod) {
case payment_provider_interface_1.PaymentMethod.WAVE:
return "WAVE";
case payment_provider_interface_1.PaymentMethod.ORANGE_MONEY:
return "OM";
case payment_provider_interface_1.PaymentMethod.CREDIT_CARD:
if (!processor ||
!Object.values(TaarihCreditCardPaymentProcessor).includes(processor)) {
throw new payment_error_1.PaymentError("Taarih error: Invalid or missing credit card processor", payment_error_1.PaymentErrorType.UNSUPPORTED_PAYMENT_METHOD);
}
return processor;
default:
throw new payment_error_1.PaymentError("Invalid payment method: " + paymentMethod);
}
}
login() {
return __awaiter(this, void 0, void 0, function* () {
const signEndUserResponse = yield this.api.post("/auth/signin-end-user", {
callingCode: this.config.callingCode,
phoneNumber: this.config.phoneNumber,
authMode: "SMS",
visitorId: this.config.visitorId,
password: this.config.password,
});
if (signEndUserResponse.data && "otpRequired" in signEndUserResponse.data) {
throw new payment_error_1.PaymentError("Taarih error: " + signEndUserResponse.data.message);
}
if (signEndUserResponse.data && "invalidData" in signEndUserResponse.data) {
throw new payment_error_1.PaymentError("Taarih error: " +
signEndUserResponse.data.message +
" " +
signEndUserResponse.data.invalidData
? JSON.stringify(signEndUserResponse.data.invalidData)
: "");
}
if (signEndUserResponse.data && "token" in signEndUserResponse.data) {
return signEndUserResponse.data;
}
throw new payment_error_1.PaymentError("Taarih error: No token in response");
});
}
checkout(options) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
let operationCode = "";
if (!("operationCode" in options)) {
operationCode =
options.paymentMethod === payment_provider_interface_1.PaymentMethod.WAVE
? "PAY_WITH_WAVE"
: "PAY_WITH_OM";
}
else if ("operationCode" in options && options.operationCode) {
operationCode = options.operationCode;
}
else {
throw new payment_error_1.PaymentError("Taarih error: operation code is required", payment_error_1.PaymentErrorType.INVALID_OPERATION_CODE);
}
if (options.currency !== payment_provider_interface_1.Currency.XOF) {
throw new payment_error_1.PaymentError("Taarih does not support the currency: " + options.currency, payment_error_1.PaymentErrorType.UNSUPPORTED_PAYMENT_METHOD);
}
const isMobileMoney = options.paymentMethod === payment_provider_interface_1.PaymentMethod.WAVE ||
options.paymentMethod === payment_provider_interface_1.PaymentMethod.ORANGE_MONEY;
const isCreditCard = options.paymentMethod === payment_provider_interface_1.PaymentMethod.CREDIT_CARD;
const user = yield this.login();
const companyId = user.legalEntityId;
let taarihCheckoutResponse;
taarihCheckoutResponse = yield this.api.post("/transaction/pos-payment", {
companyId,
amount: options.amount,
countryCode: this.config.callingCode,
mobileNumber: options.customer.phoneNumber,
paymentMethod: this.getTaarihPaymentMethod(options.paymentMethod, (_a = options.metadata) === null || _a === void 0 ? void 0 : _a.processor),
operationCode,
firstName: options.customer.firstName,
lastName: options.customer.lastName,
currency: options.currency,
externalTransactionId: options.transactionId,
accountNumber: options.accountNumber || "",
employeeId: options.employeeId
}, {
headers: Object.assign(Object.assign({}, this.api.headers), { "x-access-token": user.token }),
});
if (isMobileMoney) {
const parsedCustomerPhoneNumber = (0, libphonenumber_js_1.parsePhoneNumber)(options.customer.phoneNumber, "SN");
if (!parsedCustomerPhoneNumber.isValid()) {
throw new payment_error_1.PaymentError("Invalid phone number: " + options.customer.phoneNumber, payment_error_1.PaymentErrorType.INVALID_PHONE_NUMBER);
}
if (!parsedCustomerPhoneNumber.isPossible()) {
throw new payment_error_1.PaymentError("Phone number is not possible: " + options.customer.phoneNumber, payment_error_1.PaymentErrorType.INVALID_PHONE_NUMBER);
}
}
if (!taarihCheckoutResponse) {
throw new payment_error_1.PaymentError("Taarih error: no payment response data");
}
if (isCreditCard) {
taarihCheckoutResponse.data = (_b = taarihCheckoutResponse.data.results) === null || _b === void 0 ? void 0 : _b[0];
}
if (taarihCheckoutResponse.data &&
"externalId" in taarihCheckoutResponse.data &&
"internalId" in taarihCheckoutResponse.data &&
"payment_link" in taarihCheckoutResponse.data) {
const result = {
transactionAmount: options.amount,
transactionCurrency: options.currency,
transactionId: taarihCheckoutResponse.data.internalId,
transactionReference: taarihCheckoutResponse.data.externalId,
transactionStatus: payment_provider_interface_1.TransactionStatus.PENDING,
redirectUrl: taarihCheckoutResponse.data.payment_link,
};
return result;
}
throw new payment_error_1.PaymentError("Taarih error: response data is not valid");
});
}
checkoutMobileMoney(options) {
return __awaiter(this, void 0, void 0, function* () {
return this.checkout(options);
});
}
checkoutCreditCard(options) {
return __awaiter(this, void 0, void 0, function* () {
return this.checkout(options);
});
}
checkoutRedirect(options) {
return __awaiter(this, void 0, void 0, function* () {
throw new payment_error_1.PaymentError("Taarih redirect checkout not yet implemented", payment_error_1.PaymentErrorType.UNSUPPORTED_PAYMENT_METHOD);
});
}
refund(options) {
return __awaiter(this, void 0, void 0, function* () {
throw new payment_error_1.PaymentError("Taarih refund not yet implemented", payment_error_1.PaymentErrorType.UNSUPPORTED_PAYMENT_METHOD);
});
}
payoutMobileMoney(options) {
return __awaiter(this, void 0, void 0, function* () {
throw new payment_error_1.PaymentError("Taarih payout not yet implemented", payment_error_1.PaymentErrorType.UNSUPPORTED_PAYMENT_METHOD);
});
}
handleWebhook(rawBody) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
if ((0, lodash_1.isBuffer)(rawBody) || (0, lodash_1.isString)(rawBody)) {
console.error("Paydunya webhook body must be a parsed object, not the raw body");
return null;
}
const body = rawBody;
const taarihTransactionStatusResponse = yield this.callback(body.transactionId, body.timeInterval || 5000, body.maxAttempts || 20);
if (taarihTransactionStatusResponse.status ===
TaarihTransactionStatus.COMPLETED) {
const paymentSuccessfulEvent = {
type: payment_events_1.PaymentEventType.PAYMENT_SUCCESSFUL,
paymentMethod: "",
transactionAmount: taarihTransactionStatusResponse.amount,
transactionCurrency: payment_provider_interface_1.Currency.XOF,
transactionId: body.transactionId,
transactionReference: body.transactionId,
paymentProvider: TaarihPaymentProvider.name,
};
(_a = this.eventEmitter) === null || _a === void 0 ? void 0 : _a.emit(payment_events_1.PaymentEventType.PAYMENT_SUCCESSFUL, paymentSuccessfulEvent);
return paymentSuccessfulEvent;
}
const paymentFailedEvent = {
type: payment_events_1.PaymentEventType.PAYMENT_FAILED,
paymentMethod: "",
transactionAmount: taarihTransactionStatusResponse.amount,
transactionCurrency: payment_provider_interface_1.Currency.XOF,
transactionId: body.transactionId,
transactionReference: body.transactionId,
reason: "Payment failed",
paymentProvider: TaarihPaymentProvider.name,
};
(_b = this.eventEmitter) === null || _b === void 0 ? void 0 : _b.emit(payment_events_1.PaymentEventType.PAYMENT_FAILED, paymentFailedEvent);
return paymentFailedEvent;
});
}
callback(internalId, timeInterval = 3000, maxAttempts = 4) {
return __awaiter(this, void 0, void 0, function* () {
const user = yield this.login();
let attempts = 0;
while (true) {
const taarihTransactionStatusResponse = yield this.api.get(`/transaction/verify-transaction-status/${internalId}`, {}, {
headers: Object.assign(Object.assign({}, this.api.headers), { "x-access-token": user.token }),
});
if (taarihTransactionStatusResponse.data &&
"invalidData" in taarihTransactionStatusResponse.data) {
throw new payment_error_1.PaymentError("Taarih error: " + taarihTransactionStatusResponse.data.message);
}
const { data } = taarihTransactionStatusResponse;
if (!data) {
throw new payment_error_1.PaymentError("Taarih error: no transaction status data");
}
const status = data.status;
if (status !== TaarihTransactionStatus.PENDING) {
return (0, lodash_1.pick)(data, [
"status",
"amount",
"currency",
"bankAccountSender",
]);
}
attempts++;
if (attempts >= maxAttempts) {
return (0, lodash_1.pick)(data, [
"status",
"amount",
"currency",
"bankAccountSender",
]);
}
yield new Promise((resolve) => setTimeout(resolve, timeInterval));
}
});
}
}
exports.default = TaarihPaymentProvider;
//# sourceMappingURL=taarih.js.map