@inv2/common
Version:
A common module for v2
900 lines • 54.8 kB
JavaScript
"use strict";
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());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ZanibalService = void 0;
const axios_1 = __importDefault(require("axios"));
const form_data_1 = __importDefault(require("form-data"));
const moment_1 = __importDefault(require("moment"));
const middlewares_1 = require("../../middlewares");
const zanibal_validations_1 = require("../../validations/zanibal.validations");
const errors_1 = require("../../errors");
const email_builder_service_1 = require("../email-builder.service");
class ZanibalService {
constructor() {
this.createUpdateCustomer = (user) => __awaiter(this, void 0, void 0, function* () {
let post, emailError = null;
try {
if (!user.validatorType)
throw new errors_1.Exception({ code: 400, message: `Please specify a validator type to proceed` });
post = Object.assign(Object.assign({}, user), { active: true, birthDate: user.birthDate ? (0, moment_1.default)(user.birthDate).format('YYYY-MM-DD') : null, businessOfficeName: (['staging', 'development'].includes(process.env.NODE_ENV) ? "0000000001" : "0000000001-1"), customerGroupName: "0000000001", customerType: 'REGULAR', partnerType: "INDIVIDUAL", portfolioTypeName: "0000000203" });
if (user.id) {
['customerGroupName', 'businessOfficeName', 'customerType', 'partnerType', 'channel', 'portfolioTypeName'].forEach((key) => delete post[key]);
}
// if (picture && /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/.test(picture)) {
// post['picture'] = picture;
// post['pictureMimeType'] = help.getMimeType(picture);
// post['pictureFileName'] = 'Face Image';
// }
Object.keys(post).forEach((key) => {
if (post[key] === undefined || typeof post[key] == 'undefined' || post[key] === null)
delete post[key];
});
// console.log({postReqToCr8InZanibal: post, time: new Date()})
const error = (0, middlewares_1.Validate)(zanibal_validations_1.ZanibalValidation[user.validatorType], { body: post });
if (error) {
emailError = error;
throw new errors_1.Exception({ code: 400, message: error.message });
}
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/partner/customer/${post.id ? 'update' : 'create'}`,
method: `${post.id ? 'PUT' : 'POST'}`,
headers: this.headers,
data: JSON.stringify(post),
});
// if (!response) throw new AppError('Customer could not be created', __line, __path.basename(__filename), { status: 404 });
// // await this.createPortfolio({customerId: response.data.msgCode, label: `${firstName} ${lastName}`})
new email_builder_service_1.EmailBuilderService({ recipient: ['tadejuwon@chapelhilldenham.com', 'ahassan@chapelhilldenham.com'], sender: 'info@investnaija.com', subject: 'Zanibal Customer Creation' })
.setCustomerDetails({ firstName: 'Admin' })
.setEmailType({ type: 'zanibal-report', meta: {
status: true,
response: response.data,
payload: post,
userEmail: user.emailAddress1,
firstName: user.firstName, middleName: user.middleName, lastName: user.lastName
} }).execute();
return { success: true, status: 200, data: response.data };
}
catch (error) {
new email_builder_service_1.EmailBuilderService({ recipient: ['tadejuwon@chapelhilldenham.com'], subject: 'Zanibal Creation', sender: 'info@investnaija.com' })
.setCustomerDetails({ firstName: 'Admin' })
.setEmailType({ type: 'zanibal-report', meta: {
status: false,
error: emailError !== null && emailError !== void 0 ? emailError : error,
payload: post,
userEmail: user.emailAddress1,
firstName: user.firstName, middleName: user.middleName, lastName: user.lastName
} }).execute();
// Logger.error(`File: ${error.file || __path.basename(__filename)}, Line: ${error.line || __line} => ${error.message} <=> ${JSON.stringify(error?.response?.data)}`);
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
} //60843
});
this.createPortfolio = (_a) => __awaiter(this, [_a], void 0, function* ({ customerId, label, portfolioType = (['staging', 'development'].includes(process.env.NODE_ENV) ? "0000000001" : "ASSET_MGMT") }) {
try {
const data = { customerId, label, portfolioType };
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/portfolio/create`,
method: 'POST',
headers: this.headers,
data: JSON.stringify(data),
});
return { success: true, status: 200, message: 'Portfolio created successfully.' };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.fetchCustomer = (zanibalId) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/partner/customer/id/${zanibalId}`,
method: 'GET',
headers: this.headers
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.searchCustomerByBvn = (bvn) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/security/customer/bvn/${bvn}`,
method: 'GET',
headers: this.headers
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getSecurities = (_b) => __awaiter(this, [_b], void 0, function* ({ exchange = 'NGX', secType = 'CS', security_type = null, page = null, size = null }) {
try {
let params = ``;
if (page || size) {
if (!page || !size)
throw new errors_1.Exception({ code: 400, message: 'Pagination parameters are invalid' });
params += `&b=${page}&c=${size}`;
}
if (security_type) {
params += `&t=${security_type}`;
}
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_MDS_BASE_URL}/security/list?marketId=${exchange}&secType=${secType}`,
method: 'GET',
});
if (!response)
throw new errors_1.Exception({ code: 400, message: 'Could not fetch securities' });
return { success: true, status: 200, data: response.data.filter((sec) => ['OTC', 'MFUND', 'ETF'].indexOf(sec.secSubType) == -1) };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getCashAccount = (id) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/finance/account/customer/id/${id}`,
method: 'GET',
headers: this.headers
});
if (!response)
throw new errors_1.Exception({ code: 400, message: 'Cannot fetch customer cash account' });
return { success: true, status: 200, data: response.data.result };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getAllFunds = () => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/fund/list/active`,
method: 'GET',
headers: this.headers
});
if (!response)
throw new errors_1.Exception({ code: 400, message: 'Cannot fetch assets' });
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.createFundTransaction = (data) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: data.transType === 'SUBSCRIPTION'
? `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/fundtransaction/submit/get-cash-account`
: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/fundtransaction/submit`,
method: 'POST',
headers: this.headers,
data: JSON.stringify(data),
});
return { success: true, status: response.status, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getContractNote = (_c) => __awaiter(this, [_c], void 0, function* ({ zanibalId, portfolioId, startDate, endDate, page, size }) {
try {
let params = ``;
if (!zanibalId)
throw new errors_1.Exception({ code: 400, message: 'Zanibal Id is a required parameter.' });
if (startDate || endDate) {
if (!startDate || !endDate)
throw new errors_1.Exception({ code: 400, message: 'Error with parameters passed.' });
params += `&sd=${startDate}&ed=${endDate}`;
}
if (portfolioId)
params += `&p=${portfolioId}`;
if (page || size) {
if (!page || !size)
throw new errors_1.Exception({ code: 400, message: 'Error with parameters passed.' });
params += `&b=${page}&s=${size}`;
}
;
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/customer/contractnote/id/${zanibalId}?${params}`,
method: 'GET',
headers: this.headers
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.postFundTransaction = (txn_id) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/fundtransaction/post/${txn_id}`,
method: 'PUT',
headers: this.headers,
});
return { success: true, status: response.status, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getPortfolioBalance = (portfolioId, uParams) => __awaiter(this, void 0, void 0, function* () {
try {
let params = '';
if (uParams.startDate || uParams.endDate) {
if (!uParams.startDate || !uParams.endDate)
throw new errors_1.Exception({ code: 400, message: 'Error with parameters passed.' });
params = `?sd=${uParams.startDate}&ed=${uParams.endDate}`;
}
if (uParams.currency) {
params += (params.includes("?") ? `&cu=` : `?cu=`) + uParams.currency;
}
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/partner/portfolio-valuation-for-date-range/id/${portfolioId}${params}`,
method: 'GET',
headers: this.headers
});
if (!response)
throw new errors_1.Exception({ code: 400, message: 'Cannot fetch balance for portfolio' });
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getCustomerBalance = (zanibalId, uParams) => __awaiter(this, void 0, void 0, function* () {
try {
let params = '';
if (uParams.startDate || uParams.endDate) {
if (!uParams.startDate || !uParams.endDate)
throw new errors_1.Exception({ code: 400, message: 'Error with parameters passed.' });
params = `?sd=${uParams.startDate}&ed=${uParams.endDate}`;
}
if (uParams.currency) {
params += (params.includes("?") ? `&cu=` : `?cu=`) + uParams.currency;
}
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/partner/customer-valuation-for-date-range/id/${zanibalId}${params}`,
method: 'GET',
headers: this.headers
});
if (!response)
throw new errors_1.Exception({ code: 400, message: 'Cannot fetch balance for portfolio' });
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getFundTransactions = (_d) => __awaiter(this, [_d], void 0, function* ({ zanibalId, portfolioId, startDate, endDate, status, fundId, page, size }) {
try {
if (!zanibalId)
throw new errors_1.Exception({ code: 400, message: 'Zanibal Id is a required parameter.' });
let params = `c=${zanibalId}`;
if (page || size) {
if (!page || !size)
throw new errors_1.Exception({ code: 400, message: 'Pagination parameters are invalid' });
params += `&b=${page - 1}&s=${size}`;
}
if (portfolioId)
params += `&p=${portfolioId}`;
if (fundId)
params += `&f=${fundId}`;
if (status)
params += `&t=${status}`; // t = Transaction status. This can either be PENDING, APPROVED, or EXECUTED.
if (startDate || endDate) {
if (!startDate || !endDate || !(0, moment_1.default)(startDate).isValid() || !(0, moment_1.default)(endDate).isValid())
throw new errors_1.Exception({ code: 400, message: 'Date range parameters supplied are invalid' });
params += `&sd=${(0, moment_1.default)(startDate).format('YYYY-MM-DD')}&ed=${(0, moment_1.default)(endDate).format('YYYY-MM-DD')}`;
}
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/fundtransaction/customer/list?${params}`,
method: 'GET',
headers: this.headers
});
if (!response)
throw new errors_1.Exception({ code: 400, message: 'Cannot fetch customer balance' });
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.deleteFundTransaction = (transactionId) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/fundtransaction/delete/id/${transactionId}`,
method: 'DELETE',
headers: this.headers
});
if (!response || !response.data.success)
throw new errors_1.Exception({ code: 400, message: 'Cannot delete transaction' });
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getSecurityOverview = (_e) => __awaiter(this, [_e], void 0, function* ({ market = 'NGX', security }) {
try {
/**
* market: e.g. NGX
* security: e.g. MTNN
*/
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_MDS_BASE_URL}/security/overview/${market}/${security}`,
method: 'GET',
});
if (response.data.success == false)
throw new errors_1.Exception({ code: 400, message: `Security ${security} not found` });
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getSecurityDetail = (_f) => __awaiter(this, [_f], void 0, function* ({ market = 'NGX', security }) {
try {
/**
* market: e.g. NGX
* security: e.g. MTNN
*/
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_MDS_BASE_URL}/security/order-book-with-chart/${market}/${security}`,
method: 'GET',
});
if (response.data.success == false)
throw new errors_1.Exception({ code: 400, message: `Security ${security} not found` });
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getCustomerPortfolio = (customerZanibalId) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/portfolio/customer/id/${customerZanibalId}`,
method: 'GET',
headers: this.headers
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getCustomerPurchasingPower = (id) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/partner/customer-net-trade-balance/id/${id}`,
method: 'GET',
headers: this.headers
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getPortfolioPurchasingPower = (id) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/partner/portfolio-net-trade-balance/id/${id}`,
method: 'GET',
headers: this.headers
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getChartData = (_g) => __awaiter(this, [_g], void 0, function* ({ market = 'NGX', name, date, interval = 120 }) {
var _h, _j;
try {
/**
* market (marketId)= NGX, etc
* name=security (or secId), e.g MTNN;
* timeStamp= date- Format = 'yyyy-MM-dd'
* interval = Refresh rate, default is 120s
* */
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_MDS_BASE_URL}/security/ohlcv/${market}/${name}?fieldList=d,c,v,o,h,l,a`,
method: 'GET',
});
return { success: true, status: 200, data: (_j = (_h = response.data) === null || _h === void 0 ? void 0 : _h.result) === null || _j === void 0 ? void 0 : _j.filter((chart) => chart[0] > date) };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getOrderTerms = () => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/tradeorderterm/list/active`,
method: 'GET',
headers: this.headers
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getTopGainersLoosers = (_k) => __awaiter(this, [_k], void 0, function* ({ market = 'NGX', secType = 'CS', secSubType = 'EQTY', type = '', page = 1, size = 10 }) {
try {
let params = ``;
if (page || size) {
if (!page || !size)
throw new errors_1.Exception({ code: 400, message: 'Pagination parameters are invalid', });
params += `&b=${page}&c=${size}`;
}
if (secSubType) {
params += `&secSubType=${secSubType}`;
}
/**
* perfType: Options are MOST_ACTIVE, TOP_PERCENT_GAINER, TOP_PERCENT_LOOSER, TOP_VALUE_GAINER, TOP_VALUE_LOOSER
* secType: Security type. Options are CS, GO, COMM, FUT, NONE
* secSubType: Security sub type. Options are OTC, MFUND, ETF, EQTY
*/
const perfType = {
pg: 'TOP_PERCENT_GAINER',
pl: 'TOP_PERCENT_LOOSER',
vg: 'TOP_VALUE_GAINER',
vl: 'TOP_VALUE_LOOSER',
ma: 'MOST_ACTIVE'
};
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_MDS_BASE_URL}/security/performance?marketId=${market}&secType=${secType}&perfType=${perfType[type]}${params}`,
method: 'GET',
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getPortfolioDistribution = (id) => __awaiter(this, void 0, void 0, function* () {
try {
/**
* id: Portfolio Id
* type: Options are C=customer, P=Portfolio. If 'P', return data for the specified portfolio. If 'C', return data for all portfolios that belong to that client ID.
* cash: Should we include cash in the report (true/false)
*/
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/research/get-sector-allocation?id=${id}&type=C&cash=true`,
method: 'GET',
headers: this.headers
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getCustomerPortfolios = (customerId) => __awaiter(this, void 0, void 0, function* () {
var _l, _m, _o;
// Retrieve all the portfolios for a customer
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/portfolio/customer/id/${customerId}`,
method: 'GET',
headers: this.headers
});
let data = (_m = (_l = response.data) === null || _l === void 0 ? void 0 : _l.result) === null || _m === void 0 ? void 0 : _m.filter((p) => p.active === true);
for (const p of data) {
// p.portfolioHoldings = p.portfolioHoldings?.filter(ph => ph.securityType?.toUpperCase() == "EQUITY")
p.currentValuation.amount = (_o = p.portfolioHoldings) === null || _o === void 0 ? void 0 : _o.reduce((n, { marketValue }) => n + marketValue, 0);
}
return { success: true, status: 200, data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getPortfolioHoldings = (portfolioId) => __awaiter(this, void 0, void 0, function* () {
// Retrieve the holdings for a particular portfolio
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/portfolio/holdings/id/${portfolioId}`,
method: 'GET',
headers: this.headers
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.getTradeOrders = (id, filters) => __awaiter(this, void 0, void 0, function* () {
try {
const { page, size, orderStatus, startDate, endDate } = filters;
let params = ``;
if (page || size) {
if (!page || !size)
throw new errors_1.Exception({ code: 400, message: 'Pagination parameters are invalid' });
params += `&b=${page}&c=${size}`;
}
if (orderStatus) {
params += `&s=${orderStatus}`;
}
if (startDate || endDate) {
if (!startDate || !endDate || !(0, moment_1.default)(startDate).isValid() || !(0, moment_1.default)(endDate).isValid())
throw new errors_1.Exception({ code: 500, message: 'Date range parameters are invalid' });
params += `&sd=${(0, moment_1.default)(startDate).format('YYYY-MM-DD')}&ed=${(0, moment_1.default)(endDate).format('YYYY-MM-DD')}`;
}
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/tradeorder/portfolio/list?p=${id}${params}`,
method: 'GET',
headers: this.headers
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.cancelTradeOrders = (id) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/tradeorder/cancel/id/${id}`,
method: 'PUT',
headers: this.headers
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.validateTradeOrder = (data) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/tradeorder/validate`,
method: 'POST',
headers: this.headers,
data: JSON.stringify(data),
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.createTradeOrder = (data) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/order/tradeorder/submit`,
method: 'POST',
headers: this.headers,
data: JSON.stringify(data),
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.createCashTransaction = (data) => __awaiter(this, void 0, void 0, function* () {
var _p;
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/finance/cash-transaction/create`,
method: 'POST',
headers: this.headers,
data: JSON.stringify(data),
});
return { success: true, status: response.status, data: (_p = response.data) === null || _p === void 0 ? void 0 : _p.msgArgs[0] };
}
catch (error) {
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
this.postCashTransaction = (transaction_id) => __awaiter(this, void 0, void 0, function* () {
try {
const response = yield axios_1.default.request({
url: `${process.env.ZANIBAL_APPSERVER_BASE_URL}/finance/cash-transaction/post/id/${transaction_id}`,
method: 'PUT',
headers: this.headers,
data: null,
});
return { success: true, status: 200, data: response.data };
}
catch (error) {
// if (error?.response?.data?.msgCode) return error?.response.data
const err = error;
if (error instanceof errors_1.CustomError)
throw new errors_1.Exception(error);
throw new errors_1.Exception({ code: 500, message: err.message });
}
});
// updateCustomerPortfolio = async (zanibalId) => {
// let portfolioId = null;
// try {
// const response: { success: boolean, status: number, data: any, result: []} = await this.getCustomerPortfolio(zanibalId);
// if (response) {
// const { result } = response;
// if (result && result instanceof Array && result.length > 0) {
// const { id } = result[0];
// portfolioId = id;
// await postgres.models.customer.update(
// { zanibalPortfolioId: portfolioId },
// { where: { zanibalId } }
// );
// }
// }
// } catch (error) {
// const err = (error as Error);
// if(error instanceof CustomError) throw new Exception(error);
// throw new Exception({code: 500, message: err.message});
// }
// return portfolioId;
// };
this.createCashTransResolver = (_q) => __awaiter(this, [_q], void 0, function* ({ zanibalId, portfolioId, cashAccountId, amount, currency = "NGN", options }) {
let cashAccounts = (yield this.getCashAccount(zanibalId));
if (!cashAccounts || !cashAccounts.success)
throw new errors_1.Exception({ code: 400, message: cashAccounts.message || 'Error getting portfolio. Please try again later' });
const cashBalance = cashAccounts.data.find((c) => c.id == cashAccountId);
if (!cashBalance || cashBalance === undefined || cashBalance === null)
throw new errors_1.Exception({ code: 400, message: `No cash account on this portfolio. Please choose another portfolio or contact admin` });
if (amount > +cashBalance.clearedBalance && options.transfer)
throw new errors_1.Exception({ code: 500, message: `${amount} > ${cashBalance.clearedBalance}. Insufficient cash balance` });
let cashData = Object.assign({ amount,
cashAccountId,
currency, partnerId: zanibalId, transMethod: 'ECHANNEL', transType: options.transType, contraAcctId: options.contraAcctId }, (options.valueDate && { valueDate: options.valueDate }));
return yield this.createCashTransaction(cashData);
});
this.postCashTransactionCheck = (createCashTransResponse_1, ...args_1) => __awaiter(this, [createCashTransResponse_1, ...args_1], void 0, function* (createCashTransResponse, post = false) {
if (!createCashTransResponse || !createCashTransResponse.success)
throw new errors_1.Exception({ code: 500, message: 'error processing transaction' });
let transaction_id = createCashTransResponse.data;
if (post) {
const finalizeTransaction = yield this.postCashTransaction(transaction_id);
if (!finalizeTransaction || !finalizeTransaction.success) {
if (finalizeTransaction.msgArgs && finalizeTransaction.msgArgs[0] === 'POSTED')
return { success: true, message: 'Posted successfully', data: transaction_id };
throw new errors_1.Exception({ code: 500, message: finalizeTransaction.msgCode || 'error processing transaction' });
}
}
return { success: true, message: 'Posted successfully', data: transaction_id };
});
this.createAndPostCashTxn = (createCashTransResponse_2, ...args_2) => __awaiter(this, [createCashTransResponse_2, ...args_2], void 0, function* (createCashTransResponse, post = false) {
if (!createCashTransResponse || !createCashTransResponse.success)
throw new errors_1.Exception({ code: 500, message: 'error processing transaction' });
let transaction_id = createCashTransResponse.data;
if (post) {
const finalizeTransaction = yield this.postCashTransaction(transaction_id);
if (!finalizeTransaction || !finalizeTransaction.success) {
if (finalizeTransaction.msgArgs && finalizeTransaction.msgArgs[0] === 'POSTED')
return { success: true, message: 'Posted successfully', data: transaction_id };
throw new errors_1.Exception({ code: 500, message: finalizeTransaction.msgCode || 'error processing transaction' });
}
}
return { success: true, message: 'Posted successfully', data: transaction_id };
});
this.calculatePrice = (orderType, quantity, marketPrice, limitPrice, priceType) => __awaiter(this, void 0, void 0, function* () {
let consideration = quantity *
(priceType.toLowerCase() === 'limit' ? limitPrice : marketPrice);
let totalConsideration = (priceType.toLowerCase() === 'limit' || orderType.toLowerCase() == 'sell')
? consideration
: consideration * 0.1 + consideration;
/**
* BUY and SELL Transctions share the following variable amounts
* X-Alert Fee: this is N4.00
* VAT on X-Alert fee: this is 7.5% of Alert Fee
* Consideration: price * quantity
* Stamp Duty: this is 0.08% of consideration
* NGX/SEC Fees: this is 0.3% of consideration
*/
let alertFee = 4;
let alertFeeVAT = alertFee * 0.075;
let stampDuty = 0.0008 * totalConsideration;
let NGX_SEC_Fees = 0.003 * totalConsideration;
/**
* SELL TRANSACTION VARIABLES
* Sell transactions use the following variables:
* 7.5% VAT on Brokerage
* Alert Fees (Defined above)
* VAT on Alert Fees (Defined above)
* Stamp Duty (Defined above)
* NGX Fees (Defined above as NGX_SEC_Fees)
* CSCS Fees: this is 0.3% of consideration
* 7.5% VAT on NGX Fee and
* 7.5% on CSCS Fee
*/
let cscsFee = 0.003 * totalConsideration;
let nseFeeVAT = 0.075 * NGX_SEC_Fees;
let cscsFeeVAT = 0.075 * cscsFee;
/**
*
* Calculate Brokerage Commision and VAT on Brokerage Commision
* Brokerage Commision: this is 1.35% of the consideraton for regular customers which is what will be used on all online platforms (mobile/web)
* VAT on Brokerage Commision: this is 7.5% of brokerage commision
*
*/
let brokerageCommision = 0.0135 * totalConsideration;
let brokerageCommisionVAT = 0.075 * brokerageCommision;
/**
* Perform final calculations for posting to exchange
*/
let amount = 0;
let fees = 0;
if (orderType == 'BUY') {
fees =
alertFee +
alertFeeVAT +
stampDuty +
NGX_SEC_Fees +
brokerageCommision +
brokerageCommisionVAT;
amount = totalConsideration + fees;
}
else {
fees =
alertFee +
alertFeeVAT +
stampDuty +
NGX_SEC_Fees +
nseFeeVAT +
cscsFee +
cscsFeeVAT +
brokerageCommision +
brokerageCommisionVAT;
amount = totalConsideration - fees;
}
return {
orderType,
fees,
consideration,
totalConsideration,
amount: Math.ceil((amount + Number.EPSILON) * 100) / 100,
};
});
this.fundCashAccount = (_r) => __awaiter(this, [_r], void 0, function* ({ cashAccountId, amount, user, cashBalance = 0.00 }) {
try {
if (amount && user) {
let nairaString = new Intl.NumberFormat('NGN', {
style: 'currency',
currency: 'NGN',
minimumFractionDigits: 3,
});
if (cashBalance >= amount)
return { status: true, message: `Debit trading wallet ${nairaString.format(amount)}` };
else
throw new errors_1.Exception({ code: 500, message: 'Fund your cash account before proceeding!' });
// const wallet = await SavePlanService.getUserWallet({ customer_id: user.id });
// if (!wallet.success) throw new AppError(wallet.message ?? `Couldn't fetch wallet`, __line, __path.basename(__filename), { status: 404 });
// if (wallet.data.saveplan_users[0].total_paid >= amount - cashBalance) {
// if (user.status !== 'active') throw Error('verify your bvn to proceed!')
// let cashData = {
// amount: amount - cashBalance,
// cashAccountId: cashAccountId,
// currency: 'NGN',
// partnerId: user.zanibalId,
// transMethod: 'ECHANNEL',
// transType: 'RECEIPT',
// };
// let reference = help.generateOTCode(20, true);
// const wallet_txn = await TransactionService.postWalletTransaction({
// user, amount: (amount - cashBalance),
// description: `${cashBalance > 0 && cashBalance < amount ?
// 'Top-up trading cash account for stock purchase ' :
// 'Fund trading cash account'}`
// , source: utils.MODULE.WALLET, reference, type: 'debit', gateway: 'wallet', currency: 'NGN', module: utils.MODULE.TRADEIN, wallet: wallet.data.saveplan_users[0]
// });
// if (!wallet_txn.success) throw new AppError(wallet_txn.message ?? `Error logging debit from wallet for transaction`, __line, __path.basename(__filename), { status: 500 });
// const createCashTransResponse = await this.createCashTransaction(cashData);
// if (!createCashTransResponse || !createCashTransResponse.success) throw new AppError(`Error creating cash transaction for trade`, __line, __path.basename(__filename), { status: 500 });
// let transaction_id = createCashTransResponse.data;
// const finalizeTransaction = await this.postCashTransaction(transaction_id);
// if (!finalizeTransaction) throw new AppError(`Error posting cash transaction for trade`, __line, __path.basename(__filename), { status: 500 });
// if (!finalizeTransaction.success) throw Error(finalizeTransaction.msgCode)
// await postgres.models.transaction.update({ gatewayReference: transaction_id }, { where: { reference } });
// return {
// status: true,
// message: `${cashBalance > 0 && cashBalance < amount ?
// 'Debit trading wallet ' + nairaString.format(cashBalance) + ' + IN wallet ' + nair