UNPKG

@inv2/common

Version:

A common module for v2

900 lines 54.8 kB
"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