var global_pricelist = (function () { function toTimeString(date) { if (date instanceof Date) { return date.toISOString().replace('T', ' ').replace('Z', ''); } throw new Error('Expected Date'); } function toDate(str) { if (str instanceof Date) { return str; } else if (typeof str == 'string') { var mainparts = str.split(' '); var dparts = mainparts[0].split('-'); var tparts = mainparts[1].split(':'); return new Date(dparts[0], parseInt(dparts[1]) - 1, dparts[2], tparts[0], tparts[1], tparts[2], 0); } return new Date(0); } return { installment: { pricelists: { '1': { type: 'principal', fee_type_id: '1', tax_percentage: '0.000', data: {}, dimension: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Installment LV principal 1 (function () { // Group: Group if (true) { if (control.canceled) return; bag['setAmountRange'](100, 4000, 5); if (control.canceled) return; bag['setTermRange'](3, 60, 1); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, price: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if (true) { vars['amount'] = bag['getAmount'](); bag['setPrice'](vars['amount']); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, buildDimension: function (bag = {}) { if (!this.amounts) { var amounts = []; var terms = []; bag = Object.assign({ setAmountRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (amounts.indexOf(i) === -1) { amounts.push(i); } } }, setTermRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (terms.indexOf(i) === -1) { terms.push(i); } } } }, bag); this.dimension.evaluate(bag); amounts.sort(function (a, b) { return a - b; }); terms.sort(function (a, b) { return a - b; }); this.amounts = amounts; this.terms = terms; } return { amounts: this.amounts, terms: this.terms }; }, buildPrice: function (amount, term, pricelist_bag) { var price = null; var rate = 0; var pricebag = pricelist_bag || {}; pricebag.getAmount = function () { return parseFloat(amount); }; pricebag.getTerm = function () { return parseFloat(term); }; pricebag.setPrice = function (data) { price = data; }; pricebag.setRate = function (data) { rate = data; }; pricebag.parseFloat = parseFloat; this.price.evaluate(pricebag); return { price: parseFloat(price).toFixed(2), rate: parseFloat(rate).toFixed(10) }; } }, '2': { type: 'loan-fee', fee_type_id: '2', tax_percentage: '0.000', data: {}, dimension: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Installment LV principal 1 (function () { // Group: Group if (true) { if (control.canceled) return; bag['setAmountRange'](100, 4000, 5); if (control.canceled) return; bag['setTermRange'](3, 60, 1); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, price: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if (true) { bag['setPrice'](0); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, buildDimension: function (bag = {}) { if (!this.amounts) { var amounts = []; var terms = []; bag = Object.assign({ setAmountRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (amounts.indexOf(i) === -1) { amounts.push(i); } } }, setTermRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (terms.indexOf(i) === -1) { terms.push(i); } } } }, bag); this.dimension.evaluate(bag); amounts.sort(function (a, b) { return a - b; }); terms.sort(function (a, b) { return a - b; }); this.amounts = amounts; this.terms = terms; } return { amounts: this.amounts, terms: this.terms }; }, buildPrice: function (amount, term, pricelist_bag) { var price = null; var rate = 0; var pricebag = pricelist_bag || {}; pricebag.getAmount = function () { return parseFloat(amount); }; pricebag.getTerm = function () { return parseFloat(term); }; pricebag.setPrice = function (data) { price = data; }; pricebag.setRate = function (data) { rate = data; }; pricebag.parseFloat = parseFloat; this.price.evaluate(pricebag); return { price: parseFloat(price).toFixed(2), rate: parseFloat(rate).toFixed(10) }; } }, '4': { type: 'extension-fee', fee_type_id: '4', tax_percentage: '0.000', data: {}, dimension: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Installment LV principal 1 (function () { // Group: Group if (true) { if (control.canceled) return; bag['setAmountRange'](100, 2000, 5); if (control.canceled) return; bag['setTermRange'](3, 60, 1); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, price: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: installment extension settings (function () { // Group: Group if ([1,3].indexOf(parseInt(bag[460])) !== -1) { vars['price'] = (bag[3256] * 0.3); bag['setPrice'](vars['price']); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if ([4].indexOf(parseInt(bag[460])) !== -1) { vars['price'] = (bag[4102] * 0.3); bag['setPrice'](vars['price']); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, buildDimension: function (bag = {}) { if (!this.amounts) { var amounts = []; var terms = []; bag = Object.assign({ setAmountRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (amounts.indexOf(i) === -1) { amounts.push(i); } } }, setTermRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (terms.indexOf(i) === -1) { terms.push(i); } } } }, bag); this.dimension.evaluate(bag); amounts.sort(function (a, b) { return a - b; }); terms.sort(function (a, b) { return a - b; }); this.amounts = amounts; this.terms = terms; } return { amounts: this.amounts, terms: this.terms }; }, buildPrice: function (amount, term, pricelist_bag) { var price = null; var rate = 0; var pricebag = pricelist_bag || {}; pricebag.getAmount = function () { return parseFloat(amount); }; pricebag.getTerm = function () { return parseFloat(term); }; pricebag.setPrice = function (data) { price = data; }; pricebag.setRate = function (data) { rate = data; }; pricebag.parseFloat = parseFloat; this.price.evaluate(pricebag); return { price: parseFloat(price).toFixed(2), rate: parseFloat(rate).toFixed(10) }; } }, '51': { type: 'interest-fee', fee_type_id: '51', tax_percentage: '0.000', data: {}, dimension: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Installment LV principal 1 (function () { // Group: Group if (true) { if (control.canceled) return; bag['setAmountRange'](100, 4000, 5); if (control.canceled) return; bag['setTermRange'](3, 60, 1); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, price: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: installment lv interest staging (function () { // Group: Group if (true) { vars['varterm'] = bag['getTerm'](); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['varterm'] == 3) { bag['setPrice'](36.85); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['varterm'] == 4) { bag['setPrice'](39.17); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['varterm'] == 5) { bag['setPrice'](40.64); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['varterm'] == 6) { bag['setPrice'](41.5); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['varterm'] == 7) { bag['setPrice'](42.18); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['varterm'] == 8) { bag['setPrice'](42.59); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if ((vars['varterm'] >= 9 && vars['varterm'] <= 10)) { bag['setPrice'](43); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['varterm'] == 11) { bag['setPrice'](43.25); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if ((vars['varterm'] >= 12 && vars['varterm'] <= 20)) { bag['setPrice'](43); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['varterm'] == 21) { bag['setPrice'](42.87); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if ((vars['varterm'] >= 22 && vars['varterm'] <= 24)) { bag['setPrice'](42.5); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['varterm'] == 25) { bag['setPrice'](42.41); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if ((vars['varterm'] >= 26 && vars['varterm'] <= 28)) { bag['setPrice'](42); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['varterm'] == 29) { bag['setPrice'](41.9); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if ((vars['varterm'] >= 30 && vars['varterm'] <= 32)) { bag['setPrice'](41.5); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['varterm'] == 33) { bag['setPrice'](41.38); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if ((vars['varterm'] >= 34 && vars['varterm'] <= 44)) { bag['setPrice'](40); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if ((vars['varterm'] >= 45 && vars['varterm'] <= 49)) { bag['setPrice'](39.5); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if ((vars['varterm'] >= 50 && vars['varterm'] <= 53)) { bag['setPrice'](39); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if ((vars['varterm'] >= 54 && vars['varterm'] <= 58)) { bag['setPrice'](38.5); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if ((vars['varterm'] >= 59 && vars['varterm'] <= 60)) { bag['setPrice'](38); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, buildDimension: function (bag = {}) { if (!this.amounts) { var amounts = []; var terms = []; bag = Object.assign({ setAmountRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (amounts.indexOf(i) === -1) { amounts.push(i); } } }, setTermRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (terms.indexOf(i) === -1) { terms.push(i); } } } }, bag); this.dimension.evaluate(bag); amounts.sort(function (a, b) { return a - b; }); terms.sort(function (a, b) { return a - b; }); this.amounts = amounts; this.terms = terms; } return { amounts: this.amounts, terms: this.terms }; }, buildPrice: function (amount, term, pricelist_bag) { var price = null; var rate = 0; var pricebag = pricelist_bag || {}; pricebag.getAmount = function () { return parseFloat(amount); }; pricebag.getTerm = function () { return parseFloat(term); }; pricebag.setPrice = function (data) { price = data; }; pricebag.setRate = function (data) { rate = data; }; pricebag.parseFloat = parseFloat; this.price.evaluate(pricebag); return { price: parseFloat(price).toFixed(2), rate: parseFloat(rate).toFixed(10) }; } }, }, fee_types: { 1: 'principal', 2: 'loan_fee', 3: 'late_fee', 4: 'extension_fee', 5: 'penalty', 41: 'receivable_extension_fee', 51: 'interest_fee', 69: 'payout_fee', 85: 'cash_fee', 168: 'registration_fee', 257: 'late_fee_delay', 259: 'late_fee_delay', 261: 'late_fee_delay', 335: 'court_fee', 360: 'sale_fee', 461: 'late_fee_delay', 466: 'court_fee', }, promotions: { }, loanlimit: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if ((bag[799] == 0 && (toDate(bag['6054']).getTime() < (1714206835761-7776000000) || [4].indexOf(parseInt(bag[2538])) === -1))) { bag['setIncomeVerifyLimit'](1); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (bag[799] > 0) { bag['setIncomeVerifyLimit'](1); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (true) { bag['setSliderDefault'](2000, 24, 2); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, freshBagLimit: function (bag) { var n = { _available_limit: null, _day_lower_bound: null, _visible_limit: null, _day_limit: null, _available_day_limit: null, _lowerbound: null, _income_verify_limit: null, _reject_message: null, _slider_default: null, setSliderDefault: function (amount, term, product) { if (Number.isInteger(amount) && Number.isInteger(term) && Number.isInteger(product)) { this._slider_default = { "amount" : parseFloat(amount).toFixed(2), "term" : parseFloat(term).toFixed(0), "default_product" : product }; } }, setIncomeVerifyLimit: function (limit) { this._income_verify_limit = limit; }, setLimit: function (limit) { this._visible_limit = limit; }, setVisibleLimit: function (limit) { this._visible_limit = limit; }, setAvailableLimit: function (limit) { this._available_limit = limit; }, setHardLimit: function (limit) { this._available_limit = limit; }, getRegistrationField: function (field) { return this[field] || 0; }, getAmount: function () { return bag[-3]; }, getMaximumRepayableAmount: function () { return bag[-22]; }, setDayLowerBound: function (amount) { this._day_lower_bound = amount; }, setDayLimit: function (limit) { this._day_limit = limit; }, setAvailableDayLimit: function (limit) { this._available_day_limit = limit; }, setInstallmentsCount: function (limit) { this._day_limit = limit; }, getInstallmentsCount: function (limit) { return this._day_limit; }, setRejectLoan: function (message) { this._reject_message = message; }, setExtensionLimit: function (limit) { this._extension_limit = limit; }, setLowerBound: function (limit) { this._lowerbound = limit; }, getMonthlyPayment: function (initialPrincipal, annualInterestRate, term) { var annualInterestRate = annualInterestRate / 100; var monthlyInterestRate = annualInterestRate / 12; var divident = initialPrincipal * monthlyInterestRate; var divisor = 1 - (1 / Math.pow((1 + monthlyInterestRate), term)); return divident / divisor; }, getOverpaymentCoefficient: function (annualInterestRate, term) { var initialPrincipal = 1000; var monthlyPayment = this.getMonthlyPayment(initialPrincipal, annualInterestRate, term); var totalRepayableAmount = monthlyPayment * term; return totalRepayableAmount / initialPrincipal; }, getInterestRateApproximationFromAnnuity: function (termMonths) { var termDays = termMonths * 30; var constant = 1.000018; var resultBase = constant + (termDays * 0.0007 + 1) / termMonths; var resultLog = Math.log2(1 + 1 / termMonths); resultBase = Math.pow(resultBase, (1 / resultLog)) - 1; var interestRateApproximationFromAnnuity = ((Math.pow(resultBase, resultLog) - constant) * 12) * 100; var flooredResult = Math.floor(interestRateApproximationFromAnnuity * 100) / 100; return flooredResult; }, calculateTermUpperLimit: function (amount, maxRepayable, interest) { let monthlyInterest = (interest/100) / 12; return (isNaN(Math.ceil(Math.log(1 / (1 - ((amount * monthlyInterest) / maxRepayable))) / Math.log1p(monthlyInterest))) ? 0 : Math.ceil(Math.log(1 / (1 - ((amount * monthlyInterest) / maxRepayable))) / Math.log1p(monthlyInterest))); }, }; for (var id in bag) { if (!(id in n)) { n[id] = bag[id]; } } if ( ! (-8 in n)) { n[-8] = 88; } n["round"] = this.round return n; }, filterAvailableTerms: function (bag, checkFunction) { var limits = this.evaluateLimit(bag); var lowestAvailableTerm = null; for (var index = 0; index < limits.terms.length; index++) { var t = limits.terms[index]; bag['-2'] = t; var currentTermLimits = this.evaluateLimit(bag); if (checkFunction) { if (checkFunction(currentTermLimits)) { lowestAvailableTerm = t; break; } } else if (currentTermLimits.amounts_available.length > 0) { lowestAvailableTerm = t; break; } } return limits.terms.slice(limits.terms.indexOf(lowestAvailableTerm)); }, evaluateLimit: function (bag) { var finalAmounts_available = []; var finalAmounts_visible = []; var finalDays = []; var finalDays_available = []; var finalExtDays = []; var ibag = this.freshBagLimit(bag); var result = this.loanlimit.evaluate(ibag); this.pricelists[1].buildDimension(bag); this.pricelists[2].buildDimension(bag); this.pricelists[4].buildDimension(bag); this.pricelists[51].buildDimension(bag); for (var i = 0; i < this.pricelists[1].amounts.length; i++) { var amn = this.pricelists[1].amounts[i]; if ((ibag._available_limit == null || parseFloat(amn) <= ibag._available_limit) && (ibag._lowerbound == null || parseFloat(amn) >= ibag._lowerbound)) { finalAmounts_available.push(parseFloat(amn).toFixed(2)); } if ((ibag._visible_limit == null || parseFloat(amn) <= ibag._visible_limit) && (ibag._lowerbound == null || parseFloat(amn) >= ibag._lowerbound)) { finalAmounts_visible.push(parseFloat(amn).toFixed(2)); } } for (var i = 0; i < this.pricelists[1].terms.length; i++) { var day = this.pricelists[1].terms[i]; if ((ibag._day_limit == null || parseFloat(day) <= ibag._day_limit) && (ibag._day_lower_bound == null || parseFloat(day) >= ibag._day_lower_bound)) { finalDays.push(parseFloat(day).toFixed(0)); } if ((ibag._available_day_limit == null || parseFloat(day) <= ibag._available_day_limit) && (ibag._day_lower_bound == null || parseFloat(day) >= ibag._day_lower_bound)) { finalDays_available.push(parseFloat(day).toFixed(0)); } } for (var i = 0; i < this.pricelists[4].terms.length; i++) { var day = this.pricelists[4].terms[i]; if (ibag._extension_limit == null || parseFloat(day) <= ibag._extension_limit) { finalExtDays.push(parseFloat(day).toFixed(0)) } } return { 'pricelist-amount-limit': ibag._visible_limit, 'pricelist-amount-hard-limit': ibag._available_limit, 'pricelist-amount-lower-bound': ibag._lowerbound, 'pricelist-day-limit': ibag._day_limit, 'pricelist-available-day-limit': ibag._available_day_limit, 'pricelist-income-verify-limit': ibag._income_verify_limit, 'pricelist-day-lower-bound': ibag._day_lower_bound, 'reject_message': ibag._reject_message, amounts_available: finalAmounts_available, amounts_visible: finalAmounts_visible, terms: finalDays, terms_available: finalDays_available, extterms: finalExtDays, slider_default: ibag._slider_default } }, prolongPermissionRules: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Prohibit prolonging If all products open (function () { // Group: Group if ((bag[3251] == 1 && (bag[3252] == 1 && bag['3253'] == 1))) { bag['prohibitProlong']('Has all products open'); bag['prohibitProlongToInstallment']('Has all products open'); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: OLD VERSION OF PROLONGING=>HAS OPEN PD PROLONG TO CRL (function () { // Group: PD --> CRL FL BEFORE DUEDATE if (([1,3,4].indexOf(parseInt(bag[460])) !== -1 && ((((bag[802] < 31 && bag[2788] >= 50) && [1].indexOf(bag[2438] ? 1 : 0) !== -1) && bag[3251] == 1) && bag[3252] == 0))) { bag['prohibitProlong'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: PD --> CRL FL AFTER DUEDATE if (([1,3,4].indexOf(parseInt(bag[460])) !== -1 && (((((bag[802] > 0 && bag[802] < 31) && bag[2788] >= 50) && [1].indexOf(bag[2438] ? 1 : 0) !== -1) && bag[3251] == 1) && bag[3252] == 0))) { bag['prohibitProlong'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: PD --> CRL CL BEFORE DUEDATE if (([1,3,4].indexOf(parseInt(bag[460])) !== -1 && ((((bag[802] < 31 && bag[3252] == 0) && bag[2788] >= 50) && [0].indexOf(bag[2438] ? 1 : 0) !== -1) && bag[3251] == 1))) { bag['prohibitProlong'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: NEW VERSION OF PROLONGING to IL (function () { // Group: PDL if ((bag['3141'] == 1 && ([1,3,4].indexOf(parseInt(bag['460'])) !== -1 && (bag['2788'] >= 50 && bag[802] < 31)))) { bag['prohibitProlongToInstallment'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: NEW VERSION OF PROLONGING IL -> IL (function () { // Group: IL if ((bag['3141'] == 2 && ([1].indexOf(parseInt(bag[460])) !== -1 && (bag['2788'] >= 50 && bag[802] < 31)))) { bag['prohibitProlongToInstallment'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: NEW VERSION OF PROLONGING - TO CRL -> IL (function () { // Group: CRL if ((bag['3141'] == 3 && ([17,1,4].indexOf(parseInt(bag[460])) !== -1 && (bag['2788'] >= 50 && bag['3353'] < 31)))) { bag['prohibitProlongToInstallment'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, freshBagProlongPermissionRule: function (bag) { var n = { _loanProlongPermitted: false, _loanProlongPermittedToPayday: false, _loanProlongPermittedToInstallment: false, _loanProlongPermittedToCreditline: false, _errorMessage: null, _errorMessageProlongToPayday: null, _errorMessageProlongToInstallment: null, _errorMessageProlongToCreditline: null, _loanSettingId: null, _feetypes: [], allowProlong: function () { this._loanProlongPermitted = true; this._errorMessage = null; }, allowProlongToPayday: function () { this._loanProlongPermittedToPayday = true; this._errorMessageProlongToPayday = null; }, allowProlongToInstallment: function () { this._loanProlongPermittedToInstallment = true; this._errorMessageProlongToInstallment = null; }, allowProlongToCreditline: function () { this._loanProlongPermittedToCreditline = true; this._errorMessageProlongToCreditline = null; }, prohibitProlong: function (msg) { this._loanProlongPermitted = false; this._errorMessage = msg; }, setLoanSettings: function (id) { this._loanSettingId = id; }, prohibitProlongToPayday: function (msg) { this._loanProlongPermittedToPayday = false; this._errorMessageProlongToPayday = msg; }, prohibitProlongToInstallment: function (msg) { this._loanProlongPermittedToInstallment = false; this._errorMessageProlongToInstallment = msg; }, prohibitProlongToCreditline: function (msg) { this._loanProlongPermittedToCreditline = false; this._errorMessageProlongToCreditline = msg; }, feetypeToNewLoan: function (feetype, percentage, maxvalue) { this._feetypes.push({ "feetype": feetype, "percentage": percentage, "maxvalue": maxvalue }); }, hasLoanOpenInAllLenders: function () { return bag[-33]; }, isRequestForLoanFromPlaton: function () { return bag["is-backend"] || false; }, isRequestForLoanFromClientzone: function () { return !bag["is-backend"]; }, }; for (var id in bag) { if ((typeof bag[id] === 'string') && !isNaN(bag[id]) && isFinite(bag[id]) && typeof bag[id] !== "boolean") { bag[id] = parseFloat(bag[id]); } if (!(id in n)) { n[id] = bag[id]; } } return n; }, evaluateProlongPermisson: function (bag) { var ibag = this.freshBagProlongPermissionRule(bag); var result = this.prolongPermissionRules.evaluate(ibag); return { 'loan-prolong-permitted': ibag._loanProlongPermitted, 'loan-prolong-permitted-to-payday': ibag._loanProlongPermittedToPayday, 'loan-prolong-permitted-to-installment': ibag._loanProlongPermittedToInstallment, 'loan-prolong-permitted-to-creditline': ibag._loanProlongPermittedToCreditline, 'loan-prolong-error': ibag._errorMessage, 'loan-prolong-to-payday-error': ibag._errorMessageProlongToPayday, 'loan-prolong-to-installment-error': ibag._errorMessageProlongToInstallment, 'loan-prolong-to-creditline-error': ibag._errorMessageProlongToCreditline, 'prolong-loan-setting-id': ibag._loanSettingId, 'loan-feetype-mapping': ibag._feetypes } }, evaluateExtensionPromotions: function (now, bag, values) { var ibag = {}; var result = null; var existingpromo = null; var percentpromo = null; var percentpromos = []; var usedPromotions = []; if (bag['existing-promotions']) { var existingPromos = bag['existing-promotions'].sort(function (a, b) { return b.priority - a.priority; }); ibag = this.freshBag(bag, null); for (var i = 0; i < existingPromos.length; i++) { existingpromo = existingPromos[i]; if (existingpromo['type'] == 'percent') { percentpromo = { 'amount': parseFloat(existingpromo['amount']), 'id': existingpromo['promoId'] }; if (existingpromo['installmentIndex'] !== undefined) { // installment index can be 0 and then it wouldnt go in percentpromo['installment_index'] = existingpromo['installmentIndex'] + 1; // + 1 because for promostaging the first installment is index 1 and not 0 } if (!percentpromos[existingpromo['feeTypeId']]) { percentpromos[existingpromo['feeTypeId']] = []; } percentpromos[existingpromo['feeTypeId']].push(percentpromo); usedPromotions.push(existingpromo['promoId'].toString()); } } ibag['discounts_per'] = percentpromos; this.fillDiscounts(ibag, values); } }, extensionPermissionRules: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: SET-3547 Allow ext for all (function () { // Group: Group if (bag['1217'] !== null) { bag['allowExtension'](); bag['exit'](); if (control.canceled) return; } else { bag['allowExtension'](); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: Prohibit extension if force settledate is set (function () { // Group: Group 1 if ((bag['7560'] == 1 && bag['3141'] == 2)) { bag['prohibitExtension']('force settledate set - no extension possible CFIT-3333'); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: Remaining debt < 10 Euro (function () { // Group: Group if ((((bag[4102] > 0.02 && bag[4102] < 10) || (bag[3256] > 0.02 && bag[3256] < 10)) || bag[802] > 60)) { bag['prohibitExtension']('Fee limit reached'); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: Alow (function () { // Group: Group if (true) { bag['allowExtension'](); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; }, freshBag: function (bag, extensionPrice) { var n = { _loanExtensionPermitted: false, _errorMessage: null, allowExtension: function () { this._loanExtensionPermitted = true; this._errorMessage = null; }, prohibitExtension: function (msg) { this._loanExtensionPermitted = false; this._errorMessage = msg; } }; for (var id in bag) { if ((typeof bag[id] === 'string') && !isNaN(bag[id]) && isFinite(bag[id])) { bag[id] = parseFloat(bag[id]); } if (!(id in n)) { n[id] = bag[id]; } } n[-11] = extensionPrice; return n; } }, evaluateExtension: function (bag) { bag[-3] = bag[-3] || bag['loan-amount'] bag[-2] = bag[-2] || bag['loan-term'] bag[-1] = bag[-1] || bag['loan-extension-term'] var values = { discounts_per: {}, discounts_amn: {}, extensions: {}, total_extension_term: 0, prices: {}, feeRates: {}, discounts: {}, discounted: {} } var that = this; var now = new Date().getTime(); var amn = parseFloat(bag[-3]).toFixed(2); var term = parseFloat(bag[-2]).toFixed(0); var extterm = parseFloat(bag[-1]).toFixed(0); if (bag[-7] && (bag[-7] == '-1' || bag[-7] == '1')) { aleg: for (var id in this.pricelists) { if (!('buildPrice' in this.pricelists[id])) { if (!(amn in this.pricelists[id].data)) { var pamn = '0.0'; for (var iamn in this.pricelists[id].data) { if (parseFloat(iamn) > parseFloat(amn)) { if (bag[-7] == '1') { amn = iamn; break aleg; } else { if (parseFloat(pamn) == 0.0) { throw new Error('There is no smaller amount than ' + amn + ' to round down to for pricelist with id ' + id); } amn = pamn; break aleg; } } pamn = iamn; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '1') { amn = pamn; break aleg; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '-1') { amn = pamn; break aleg; } } } } } for (var id in this.pricelists) { if ( id != 4 ) { continue; } if ('buildPrice' in this.pricelists[id]) { var save = bag['pricelist_bag']; bag['pricelist_bag'] = {}; for (var x in save) { bag['pricelist_bag'][x] = save[x]; } for (var x in bag) { if (x != 'pricelist_bag') { bag['pricelist_bag'][x] = bag[x]; } } var pricelist_bag = {}; for (var item in bag['pricelist_bag']) { pricelist_bag[item] = bag['pricelist_bag'][item]; } var pricelistResult = this.pricelists[id].buildPrice(amn, extterm, pricelist_bag); var price = parseFloat(pricelistResult.price); var feeRate = parseFloat(pricelistResult.rate); values.prices[id] = price; values.feeRates[id] = feeRate; } else { if (!this.pricelists[id].data) continue; if (!(amn in this.pricelists[id].data)) { throw new Error('Invalid Amount ' + amn + ' for pricelist with id ' + id); } if (!extterm in this.pricelists[id].data[amn]) { throw new Error('Invalid Term ' + extterm + ' for pricelist with id ' + id + ' for amount ' + amn); } values.prices[id] = parseFloat(this.pricelists[id].data[amn][extterm]); values.feeRates[id] = 0; } } if ('existing-fees' in bag) { for (var id in bag['existing-fees']) { if (bag['existing-fees'][id].amount == 0) { continue; } if (!values.prices[id]) { values.prices[id] = 0; } values.prices[id] += bag['existing-fees'][id].amount; } } this.evaluateExtensionPromotions(now, bag, values); var details2 = { 'percent-discounts' : {}, 'amount-discounts' : {}, 'extensions': {}, original: {}, discount: {}, final: {} }; for (var id in values.prices) { var feeType = null; if (id in this.pricelists) { feeType = this.pricelists[id].type; } else if (id in bag['existing-fees']) { feeType = bag['existing-fees'][id].type; } var discountPercentAr = values.discounts_per[id]; var discountPercent = 0; if (discountPercentAr) { details2['percent-discounts'][feeType] = discountPercentAr; for (var i = 0; i < discountPercentAr.length; i++) { discountPercent += parseFloat(discountPercentAr[i].amount); } } var discountAmountAr = values.discounts_amn[id]; var discountAmount = 0; if (discountAmountAr) { details2['amount-discounts'][feeType] = discountAmountAr; for (var i = 0; i < discountAmountAr.length; i++) { discountAmount += parseFloat(discountAmountAr[i].amount); } } var discount = Math.min(values.prices[id] * discountPercent / 100 + discountAmount, values.prices[id]); var finalAmount = values.prices[id] - discount; values.discounts[id] = parseFloat(discount.toFixed(2)); values.discounted[id] = parseFloat(finalAmount.toFixed(2)); details2.original[feeType] = values.prices[id]; details2.discount[feeType] = values.discounts[id]; details2.final[feeType] = values.discounted[id]; } var ibag = null; var extensionPrice = values.discounted[4]; ibag = this.extensionPermissionRules.freshBag(bag, extensionPrice); this.extensionPermissionRules.evaluate(ibag); var calc_loan_duedate = bag['loan_duedate'] ? new Date(Date.parse(bag['loan_duedate'])) : null; if (calc_loan_duedate) { var calc_loan_is_payday = bag['loan_is_payday']; var calc_extension_permitted = ibag == null || (!ibag._errorMessage && ibag._loanExtensionPermitted); var calc_term = parseInt(extterm); var calc_duedate = null; var calc_now = new Date(); var calc_late = calc_loan_duedate < calc_now; var calc_actDuedate = calc_late ? calc_now : calc_loan_duedate; if (calc_extension_permitted) { calc_duedate = calc_actDuedate; if (calc_loan_is_payday) { calc_duedate.setDate(calc_duedate.getDate() + calc_term); } else { calc_duedate.setMonth(calc_duedate.getMonth() + calc_term); } calc_duedate = (calc_duedate.toISOString()).substr(0, 10); } } return { 'loan-amount': bag[-3], 'loan-term': bag[-2], 'loan-extension-term': bag[-1], 'loan-extension-fees': values.discounted[4], 'loan-extension-duedate': calc_duedate, 'loan-extension-permitted': ibag._loanExtensionPermitted, 'loan-extension-error': ibag._errorMessage, 'loan-original-extension-fees': values.prices[4], 'loan-free-extension': values.total_extension_term, details: details2, }; }, installmentSettings: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; return control; }, freshBag: function(bag) { var n = { promotableInstallmentsCount: 0, setPromotableInstallmentsCount: function (count) { this.promotableInstallmentsCount = count; }, setInstallmentFee: function (dummy, dummy2) {}, setExtensionPrice: function (dummy) {}, getSum: function (dummy) { return 0; }, getOpen: function (dummy) { return 0; }, getRemaining: function (dummy) { return 0; }, round: function (dummy) { return 0; } }; for (var id in bag) { if (!(id in n)) { n[id] = bag[id]; } } return n; }, evaluatePromotableInstallments: function(amount, term, bag) { var ibag = this.freshBag(bag); ibag.getAmount = function () { return amount; }; ibag.getTerm = function () { return term; }; this.evaluate(ibag); return ibag; }, }, evaluateInstallments: function (bag, promotions) { // bag[-42] => for active recalc v3 var recalc3 = false; if (bag[-42]) { bag[-42].forEach(function (version) { if (version.product_id == 2 && version.recalc_version > 3) { recalc3 = true; } }); } var firstInstallmentDate = bag['first-installment-date']; if (firstInstallmentDate) { firstInstallmentDate.setMinutes(0); firstInstallmentDate.setHours(0); firstInstallmentDate.setSeconds(0); } var amount = parseFloat(bag['loan-amount']); var term = parseFloat(bag['loan-term']); var loan_fee = parseFloat(bag['loan-fee']); var original_amount = parseFloat(bag['original-amount']) || 0; var fast_transfer_fee = 0; var fast_transfer_fee_split = 1; var additional_amount_payout_date = null; var interest_rate = parseFloat(bag['interest-rate']) / 100; const preparation_fee = 0; var promotableInstallmentsCount = parseFloat(bag['promotable-installments-count']); var now = bag['calculation-date'] ? new Date(bag['calculation-date']) : new Date(); // update now without time var now = new Date(now.getFullYear(), now.getMonth(), now.getDate()); var due = new Date(now.getFullYear(), now.getMonth() + term, now.getDate()); // we dont allow all installments to be promotable/promoteable if (promotableInstallmentsCount && (term - promotableInstallmentsCount < 1)) { promotableInstallmentsCount = 0; } var calcTerm = term - promotableInstallmentsCount; function daysBetween(t1, t2) { var oneDay = 24 * 60 * 60 * 1000; return Math.round(Math.abs((t1.getTime() - t2.getTime())/oneDay)); } function dateWithoutTime(date) { var newdate = date ? new Date(date) : new Date(); newdate.setMinutes(0); newdate.setHours(0); newdate.setSeconds(0); return newdate; } function getIntervalJson(interval) { var yearsSplit = interval.split('y'); var monthsSplit = yearsSplit[1].split('m'); var daysSplit = monthsSplit[1].split('d'); return { years: parseInt(yearsSplit[0]), months: parseInt(monthsSplit[0]), days: parseInt(daysSplit[0]) }; } function getIntervalNewDate(paymentDate, interval) { var intervalJson = getIntervalJson(interval); var intervalNewDate = new Date(paymentDate); intervalNewDate.setFullYear(paymentDate.getFullYear() + intervalJson.years); intervalNewDate.setMonth(paymentDate.getMonth() + intervalJson.months); intervalNewDate.setDate(paymentDate.getDate() + intervalJson.days); return intervalNewDate; } function getMonthlyPaymentDate(date, bag) { if (!bag || !bag['grace-period-days']) { return date; } var monthlyPaymentDate = new Date(date); monthlyPaymentDate.setDate(date.getDate() + parseInt(bag['grace-period-days'])); return monthlyPaymentDate; } function getNextPaymentDate(paymentDate, targetDay, bag) { if (bag && 'use-interval' in bag && bag['use-interval']) { return getIntervalNewDate(paymentDate, bag['interval']); } var followingMonth, followingYear, lastOfFollowingMonth, newDate; if (paymentDate.getMonth() === 11) { followingMonth = 0; followingYear = paymentDate.getFullYear() + 1; } else { followingMonth = paymentDate.getMonth() + 1; followingYear = paymentDate.getFullYear(); } lastOfFollowingMonth = new Date(followingYear, followingMonth + 1, 0); newDate = dateWithoutTime(paymentDate); if(lastOfFollowingMonth.getDate() < targetDay) { newDate.setMonth(lastOfFollowingMonth.getMonth()); newDate.setDate(0); } else { newDate.setMonth(paymentDate.getMonth() + 1); newDate.setDate(targetDay); } return newDate; } if (bag['additional-payout-date']) { additional_amount_payout_date = new Date(bag['additional-payout-date']); } function calcPromotionDiscount(feeAmount, feeTypeId, currentInstallmentIndex, promotions) { var totalReduc = 0; if (promotions.discounts_per[feeTypeId]) { var promos = promotions.discounts_per[feeTypeId]; for (var i = 0; i < promos.length; i++) { var p = promos[i]; var a = (p.amount / 100) * feeAmount; if (p.installment_index < 0) { p.installment_index = term + p.installment_index + 1; } if (p.installment_index - 1 === currentInstallmentIndex) { totalReduc += a; } else if (p.installment_index === undefined) { totalReduc += a; } }; } if (promotions.discounts_amn[feeTypeId]) { var promos = promotions.discounts_amn[feeTypeId]; for (var z = 0; z < promos.length; z++) { var p = promos[z]; if (p.installment_index < 0) { p.installment_index = term + p.installment_index + 1; } if (p.installment_index - 1 === currentInstallmentIndex) { totalReduc += p.amount; } else if (p.installment_index === undefined) { totalReduc += p.amount; } }; } return Math.max(0, (feeAmount - totalReduc)); } var freeze_now = dateWithoutTime(now); // Todo up var make_schedule = function(pmt) { var paymentDate = new Date(freeze_now), oldDate = paymentDate, repayment_interval; // adapt repayment interval if (firstInstallmentDate) { firstInstallmentDate.setSeconds(1); repayment_interval = Math.floor((firstInstallmentDate - paymentDate) / (1000 * 60 * 60 * 24)); paymentDate = new Date(firstInstallmentDate); } else { repayment_interval = new Date(paymentDate.getFullYear(), paymentDate.getMonth() + 1, 0, 0, 0, 0, 0).getDate(); paymentDate.setMonth(paymentDate.getMonth() + 1); } var schedule = []; var curr_principal = amount; var loan_fee_per_interval = loan_fee / calcTerm; var interest; var curr_interest; var old_year_days, new_year_days; var interest_before_additional_amount, days_to_additonal_amount; var days_to_additional_amount_in_old_year, days_to_additional_amount_in_new_year; var repayment; if (recalc3) { // recalc 3 installment fees cannot have remaining debt left from rounding or cutting loan_fee_per_interval = Math.floor(loan_fee / calcTerm * 100) / 100; } var target_day = paymentDate.getDate(); for (var i = 0; i < calcTerm; i += 1) { // Check for partial payment if (recalc3 && additional_amount_payout_date && i === 0 && original_amount > 0 && paymentDate > additional_amount_payout_date) { curr_principal = original_amount; days_to_additonal_amount = daysBetween(oldDate, additional_amount_payout_date); if (additional_amount_payout_date.getFullYear() > oldDate.getFullYear()) { old_year_days = daysBetween(new Date(oldDate.getFullYear(), 0, 1), new Date(oldDate.getFullYear() + 1, 0, 1)); new_year_days = daysBetween(new Date(additional_amount_payout_date.getFullYear(), 0, 1), new Date(additional_amount_payout_date.getFullYear() + 1, 0, 1)); days_to_additional_amount_in_old_year = daysBetween(oldDate, new Date(oldDate.getFullYear() + 1, 0, 1)); days_to_additional_amount_in_new_year = daysBetween(new Date(additional_amount_payout_date.getFullYear(), 0, 1), additional_amount_payout_date); // this is because recalc 3 fees always start with the next day at 00:00:00 days_to_additional_amount_in_old_year--; days_to_additional_amount_in_new_year++; interest_before_additional_amount = ( (curr_principal * (interest_rate / old_year_days * days_to_additional_amount_in_old_year )) + (curr_principal * (interest_rate / new_year_days * days_to_additional_amount_in_new_year )) ); } else { old_year_days = daysBetween(new Date(oldDate.getFullYear(), 0, 1), new Date(oldDate.getFullYear() + 1, 0, 1)); interest_before_additional_amount = curr_principal * (interest_rate / old_year_days * days_to_additonal_amount); days_to_additional_amount_in_old_year = days_to_additonal_amount; days_to_additional_amount_in_new_year = 0; } oldDate = additional_amount_payout_date; curr_principal = amount; } else { interest_before_additional_amount = 0; days_to_additional_amount_in_old_year = 0; days_to_additional_amount_in_new_year = 0; } // Check for leap year if (paymentDate.getFullYear() > oldDate.getFullYear()) { old_year_days = daysBetween(new Date(oldDate.getFullYear(), 0, 1), new Date(oldDate.getFullYear() + 1, 0, 1)); new_year_days = daysBetween(new Date(paymentDate.getFullYear(), 0, 1), new Date(paymentDate.getFullYear() + 1, 0, 1)); var installment_days_in_old_year = daysBetween(oldDate, new Date(oldDate.getFullYear() + 1, 0, 1)) - days_to_additional_amount_in_old_year, installment_days_in_new_year = daysBetween(new Date(paymentDate.getFullYear(), 0, 1), paymentDate) - days_to_additional_amount_in_new_year; if (recalc3) { // this is because recalc 3 fees always start with the next day at 00:00:00 installment_days_in_old_year--; installment_days_in_new_year++; } var interestRateOldYear = interest_rate / old_year_days * (installment_days_in_old_year - days_to_additional_amount_in_old_year); var interestRateNewYear = interest_rate / new_year_days * (installment_days_in_new_year - days_to_additional_amount_in_new_year); interest = (curr_principal * interestRateOldYear) + (curr_principal * interestRateNewYear) + interest_before_additional_amount; curr_interest = Math.floor(interest * 100) / 100; } else { old_year_days = daysBetween(new Date(oldDate.getFullYear(), 0, 1), new Date(oldDate.getFullYear() + 1, 0, 1)); var interestRate = interest_rate / old_year_days * (repayment_interval - days_to_additional_amount_in_old_year - days_to_additional_amount_in_new_year); interest = (curr_principal * interestRate) + interest_before_additional_amount; curr_interest = Math.floor(interest * 100) / 100; } var principal = Math.max(0, pmt - loan_fee_per_interval - curr_interest); var loanfee = calcPromotionDiscount(loan_fee_per_interval, 2, i, promotions); var interest = calcPromotionDiscount(curr_interest, 51, i, promotions); // --------------- creating the installment -------------------- var og_principal = parseFloat(Math.max(0, pmt - loan_fee_per_interval - curr_interest)); var og_loanfee = parseFloat(loan_fee_per_interval); var og_preparationFee = parseFloat(0); var og_fastTransferFee = parseFloat(0); var og_interest = parseFloat(curr_interest); var disc_principal = parseFloat(principal); var disc_loanfee = parseFloat(loanfee); var disc_preparationFee = parseFloat(og_preparationFee); var disc_fastTransferFee = parseFloat(og_fastTransferFee); var disc_interest = parseFloat(interest); if (i == 0) { og_preparationFee = parseFloat(preparation_fee); disc_preparationFee = Math.min(og_preparationFee, disc_loanfee); disc_loanfee = disc_loanfee - disc_preparationFee; og_fastTransferFee = parseFloat(fast_transfer_fee); disc_fastTransferFee = og_fastTransferFee; } if (i + 1 < fast_transfer_fee_split) { og_fastTransferFee = Math.ceil(fast_transfer_fee / fast_transfer_fee_split * 100) / 100; disc_fastTransferFee = og_fastTransferFee; } else if (i + 1 == fast_transfer_fee_split && i > 0) { og_fastTransferFee = parseFloat(fast_transfer_fee - (Math.ceil(fast_transfer_fee / fast_transfer_fee_split * 100) / 100) * i); disc_fastTransferFee = og_fastTransferFee; } repayment = { date: paymentDate, original: { 1: og_principal, 2: og_loanfee, 51: og_interest }, discounted: { 1: disc_principal, 2: disc_loanfee, 51: disc_interest }, discounts: {}, payment: disc_principal + disc_loanfee + disc_interest + disc_preparationFee + disc_fastTransferFee }; repayment.discounts[1] = parseFloat(repayment.original[1] - repayment.discounted[1]); repayment.discounts[2] = parseFloat(repayment.original[2] - repayment.discounted[2]); repayment.discounts[51] = parseFloat(repayment.original[51] - repayment.discounted[51]); curr_principal -= principal; schedule.push(repayment); oldDate = paymentDate; paymentDate = getNextPaymentDate(paymentDate, target_day, null); repayment_interval = daysBetween(oldDate, paymentDate); } // Return schedule and remaining principal return { schedule: schedule, leftover: curr_principal, }; }; var guessRounding = function(value) { if (recalc3) { return Math.round(((value) / 2) * 100) / 100; } else { return Math.ceil(((value) / 2) * 100) / 100; } } var days_diff = Math.floor((due - now) / (1000 * 60 * 60 * 24)); var min_rep = (amount + loan_fee) / calcTerm; var max_rep = (amount + loan_fee + (amount * (interest_rate / 366 * days_diff))) / calcTerm; var old_guess = undefined; var guess = guessRounding(min_rep + max_rep); var sched = make_schedule(guess); var tries = 0; while (Math.abs(sched.leftover) > 0.00001 && guess !== old_guess && tries < 40) { if (sched.leftover > 0) { min_rep = guess; guess = guessRounding(guess + max_rep); } else { max_rep = guess; guess = guessRounding(guess + min_rep); } sched = make_schedule(guess); tries += 1; } var last = sched.schedule.slice(-1)[0]; last.payment += sched.leftover; last.original[1] += sched.leftover; last.discounted[1] += sched.leftover; var paymentDate = last.date; for (var j = 0; j < promotableInstallmentsCount; j += 1) { paymentDate = new Date(paymentDate.getFullYear(), paymentDate.getMonth() + 1, paymentDate.getDate()); var special_loanfee = calcPromotionDiscount(last.payment, 2, calcTerm + j, promotions); var promotableInstallment = { date: paymentDate, original: { 1: 0, 2: last.payment, 51: 0 }, discounted: { 1: 0, 2: special_loanfee, 51: 0 }, discounts: { }, payment: special_loanfee }; promotableInstallment.discounts[1] = parseFloat(promotableInstallment.original[1] - promotableInstallment.discounted[1]); promotableInstallment.discounts[2] = parseFloat(promotableInstallment.original[2] - promotableInstallment.discounted[2]); promotableInstallment.discounts[51] = parseFloat(promotableInstallment.original[51] - promotableInstallment.discounted[51]); sched.schedule.push(promotableInstallment); } return sched; }, calculateAPR: function (startAmount, values) { var PRECISION = 0.00001; var MAX_ATTEMPTS = 1000; var bsMinB = -0.999999999999; var bsMaxB = 2000000000; var principal = startAmount; var attempts = 0; var repaymentTotal = 0; var APRRate = 1; while (Math.abs(repaymentTotal - principal) > PRECISION) { if (attempts >= MAX_ATTEMPTS || (bsMaxB == bsMinB) && (bsMaxB == APRRate)) { return NaN; } attempts++; if (attempts > 1) { if (repaymentTotal < principal) { bsMaxB = APRRate; } else { bsMinB = APRRate; } APRRate = bsMaxB - (bsMaxB - bsMinB) / 2; } repaymentTotal = 0; for (var i = 0; i < values.length; i++) { var rt = Math.pow(1 + APRRate, (i + 1) / 12); // 12 = compounding period repaymentTotal += values[i].payment / rt; } } return APRRate * 100; }, DaysBetween: function(date1, date2) { var oneDay = 24*60*60*1000; return Math.round(Math.abs((date1.getTime() - date2.getTime())/oneDay)); }, XNPV: function(rate, values, daysInYear) { var payment_fee_percentage = 0.00 / 100; var xnpv = 0.0; var firstDate = new Date(values[0].date); for (var i = 0, max = values.length; i < max; i += 1) { var tmp = values[i]; var value; if (tmp.payment < 0) { value = tmp.payment * (1 - payment_fee_percentage); } else { value = tmp.payment * (1 + payment_fee_percentage); } var date = new Date(tmp.date); xnpv += value / Math.pow(1 + rate, this.DaysBetween(firstDate, date)/daysInYear); } return xnpv; }, aprForPayday: function(initialAmount, term, toRepay, daysInYear) { var payment_fee_percentage = 0.00 / 100; return Math.round((Math.pow(toRepay * (1 + payment_fee_percentage) / (initialAmount * (1 - payment_fee_percentage)), daysInYear / term) - 1) * 10000) / 100; }, arForPayday: function (initialAmount, term, toRepay, daysInYear) { var price = toRepay - initialAmount; return Math.round(price / initialAmount * (daysInYear / term) * 10000) / 100; }, rpyForPayday: function (initialAmount, term, toRepay, daysInYear) { var price = toRepay - initialAmount; return Math.round((price / initialAmount / term * daysInYear) * 10000) / 100; }, rpmForPayday: function (initialAmount, term, toRepay, daysInYear) { var price = toRepay - initialAmount; return Math.round((price / initialAmount / term * daysInYear / 12) * 10000) / 100; }, rpdForPayday: function (initialAmount, term, toRepay) { var price = toRepay - initialAmount; return Math.round((price / initialAmount / term) * 10000) / 100; }, XIRR: function(initialAmount, values, guess, forcePayoutDate, daysInYear) { if (!guess) guess = 0.1; var payoutDate = forcePayoutDate ? new Date(forcePayoutDate) : new Date(); payoutDate.setMinutes(0); payoutDate.setHours(0); payoutDate.setSeconds(0); values = values.slice(0); values.unshift({payment:-initialAmount, date:payoutDate}); var x1 = 0.0; var x2 = guess; var f1 = this.XNPV(x1, values, daysInYear); var f2 = this.XNPV(x2, values, daysInYear); for (var i = 0; i < 100; i++) { if ((f1 * f2) < 0.0) break; if (Math.abs(f1) < Math.abs(f2)) { f1 = this.XNPV(x1 += 1.6 * (x1 - x2), values, daysInYear); } else { f2 = this.XNPV(x2 += 1.6 * (x2 - x1), values, daysInYear); } }; if ((f1 * f2) > 0.0) return null; var f = this.XNPV(x1, values, daysInYear); if (f < 0.0) { var rtb = x1; var dx = x2 - x1; } else { var rtb = x2; var dx = x1 - x2; }; for (var i = 0; i < 100; i++) { dx *= 0.5; var x_mid = rtb + dx; var f_mid = this.XNPV(x_mid, values, daysInYear); if (f_mid <= 0.0) rtb = x_mid; if ((Math.abs(f_mid) < 1.0e-6) || (Math.abs(dx) < 1.0e-6)) return Math.max(0, x_mid * 100); }; return null; }, rpyForInstallment: function (interestRate) { return interestRate; }, rpmForInstallment: function (interestRate) { return interestRate / 12; }, rpdForInstallment: function (interestRate, daysInYear) { return interestRate / daysInYear; }, // add base functions fillDiscounts: function (ibag, values) { for (var id in ibag.discounts_per) { if (!(id in values.discounts_per)) { values.discounts_per[id] = []; } for (var i = 0; i < ibag.discounts_per[id].length; i++) { values.discounts_per[id].push(ibag.discounts_per[id][i]); } } for (var id in ibag.discounts_amn) { if (!(id in values.discounts_amn)) { values.discounts_amn[id] = []; } for (var i = 0; i < ibag.discounts_amn[id].length; i++) { values.discounts_amn[id].push(ibag.discounts_amn[id][i]); } } if (!('designations' in values)) { values.designations = {}; } for (var promo_id in ibag.designations) { values.designations[promo_id] = ibag.designations[promo_id]; } for (var promo_id in ibag.customer_data) { if (!('customer_data' in values)) { values.customer_data = {}; } values.customer_data[promo_id] = ibag.customer_data[promo_id]; } var totalTerm = 0; for (var i = 0; i < ibag.extensions.length; i++) { var promo_id = ibag.extensions[i].id; if (!(promo_id in values.extensions)) { values.extensions[promo_id] = 0; } values.extensions[promo_id] += ibag.extensions[i].term; values.total_extension_term += ibag.extensions[i].term; } }, round: function (value, interval, mode) { var returnValue = null; var value = value / interval; switch (mode) { case 0: //FUNCTION_ROUND_FLOOR returnValue = Math.floor(value); break; case 1: //FUNCTION_ROUND_CEIL returnValue = Math.ceil(value); break; case 3: //FUNCTION_ROUND_HALF_DOWN returnValue = -Math.round(-value); break; case 2: //FUNCTION_ROUND_HALF_UP returnValue = Math.round(value); break; } return returnValue ? returnValue / (1 / interval) : returnValue; }, freshBag: function (bag, promo_id) { var that = this; var n = { discounts_per: {}, discounts_amn: {}, extensions: [], designations: {}, customer_data: {}, addInstallmentPromotionPercent: function (feetype, amount, installment_index) { if (!(feetype in this.discounts_per)) { this.discounts_per[feetype] = []; } this.discounts_per[feetype].push({ amount: amount, id: promo_id, installment_index: installment_index }); }, addInstallmentPromotion: function (feetype, amount, installment_index) { if (!(feetype in this.discounts_amn)) { this.discounts_amn[feetype] = []; } this.discounts_amn[feetype].push({ amount: amount, id: promo_id, installment_index: installment_index }); }, addDiscountPercent: function (feetype, amount) { if (!(feetype in this.discounts_per)) { this.discounts_per[feetype] = []; } this.discounts_per[feetype].push({ amount: amount, id: promo_id }); }, addDiscount: function (feetype, amount) { if (!(feetype in this.discounts_amn)) { this.discounts_amn[feetype] = []; } this.discounts_amn[feetype].push({ amount: amount, id: promo_id }); }, setDesignation: function (designation) { this.designations[promo_id] = designation; }, addFreeExtension: function (term) { this.extensions.push({ term: term, id: promo_id }); }, getCustomerData: function (type) { if ('customer-data' in bag && type in bag['customer-data']) { return bag['customer-data'][type]; } else { return null; } }, setCustomerData: function (type, data) { if (!(promo_id in this.customer_data)) { this.customer_data[promo_id] = []; } this.customer_data[promo_id].push({ type: type, data: data }); }, round: that.round, }; for (var id in bag) { if (!(id in n)) { n[id] = bag[id]; } } return n; }, evaluateLoanPromotions: function (now, bag, values) { var ibag = {}; var existingpromo = null; var percentpromo = null; var percentpromos = []; var usedPromotions = []; if (bag['existing-promotions']) { var existingPromos = bag['existing-promotions'].sort(function (a, b) { return b.priority - a.priority; }); ibag = this.freshBag(bag, null); for (var i = 0; i < existingPromos.length; i++) { existingpromo = existingPromos[i]; if (existingpromo['type'] == 'percent') { percentpromo = { 'amount': parseFloat(existingpromo['amount']), 'id': existingpromo['promoId'] }; if (existingpromo['installmentIndex'] !== undefined) { // installment index can be 0 and then it wouldnt go in percentpromo['installment_index'] = existingpromo['installmentIndex'] + 1; // + 1 because for promostaging the first installment is index 1 and not 0 } if (!percentpromos[existingpromo['feeTypeId']]) { percentpromos[existingpromo['feeTypeId']] = []; } percentpromos[existingpromo['feeTypeId']].push(percentpromo); usedPromotions.push(existingpromo['promoId'].toString()); } } ibag['discounts_per'] = percentpromos; this.fillDiscounts(ibag, values); } var quit = false; }, addPromotionResult: function (now, bag, values, start, end, id) { var ibag = {}; var result = null; if (start < now && now < end) { ibag = this.freshBag(bag, id); result = this.promotions[id].evaluate(ibag); this.fillDiscounts(ibag, values); return result.quit; } return false; }, evaluate: function (bag) { bag[-3] = bag[-3] || bag['loan-amount'] bag[-2] = bag[-2] || bag['loan-term'] var values = { discounts_per: {}, discounts_amn: {}, extensions: {}, total_extension_term: 0, prices: {}, feeRates: {}, discounts: {}, discounted: {}, prices_without_tax: {}, discounted_without_tax: {}, discounts_without_tax: {} } var that = this; var now = new Date().getTime(); var amn = parseFloat(bag[-3]).toFixed(2); var term = parseFloat(bag[-2]).toFixed(0); var extterm = bag[-1] == undefined ? term : parseFloat(bag[-1]).toFixed(0); // apr calculation is by default true, unless apr is set var apr = bag[-13] == undefined ? true : bag[-13]; var excludeFeesFromApr = bag['exclude-fees-from-apr'] == undefined ? [] : bag['exclude-fees-from-apr']; if (bag[-7] && (bag[-7] == '-1' || bag[-7] == '1')) { aleg: for (var id in this.pricelists) { if (!('buildPrice' in this.pricelists[id])) { if (!(amn in this.pricelists[id].data)) { var pamn = '0.0'; for (var iamn in this.pricelists[id].data) { if (parseFloat(iamn) > parseFloat(amn)) { if (bag[-7] == '1') { amn = iamn; break aleg; } else { if (parseFloat(pamn) == 0.0) { throw new Error('There is no smaller amount than ' + amn + ' to round down to for pricelist with id ' + id); } amn = pamn; break aleg; } } pamn = iamn; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '1') { amn = pamn; break aleg; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '-1') { amn = pamn; break aleg; } } } } } for (var id in this.pricelists) { if (bag['ignore-fee'] && bag['ignore-fee'][this.fee_types[id]]) { values.prices[id] = 0; continue; } if ('buildPrice' in this.pricelists[id]) { bag['pricelist_bag'] = bag['pricelist_bag'] || {}; for (var x in bag) { if (x != 'pricelist_bag') { bag['pricelist_bag'][x] = bag[x]; } } var pricelistResult = this.pricelists[id].buildPrice(amn, term, bag['pricelist_bag']); values.prices[id] = pricelistResult.price; values.feeRates[id] = pricelistResult.rate; } else { if (!(amn in this.pricelists[id].data)) { throw new Error('Invalid Amount ' + amn + ' for pricelist with id ' + id); } if (!term in this.pricelists[id].data[amn]) { throw new Error('Invalid Term ' + term + ' for pricelist with id ' + id + ' for amount ' + amn); } values.prices[id] = this.pricelists[id].data[amn][term]; values.feeRates[id] = 0; } if (this.pricelists[id].tax_percentage && this.pricelists[id].tax_percentage > 0) { values.prices_without_tax[id] = (values.prices[id] / (1 + parseFloat(this.pricelists[id].tax_percentage))).toFixed(2); } } this.evaluateLoanPromotions(now, bag, values); var details2 = { 'percent-discounts': {}, 'amount-discounts': {}, extensions: {}, original: {}, discount: {}, final: {}, tax_percentage: {}, without_tax: { original: {}, final: {}, discount: {} } }; var productId = true ? 2 : 1; var recalcVersion = 0; if (bag[-42]) { bag[-42].forEach(function (version) { if (version.product_id == productId) { recalcVersion = version.recalc_version; } }); } // if there are installment settings, call the installment handler var interest_rate = values.prices[51]; var fast_transfer_fee_split = null; var _promotable_installments_count = this.installmentSettings.evaluatePromotableInstallments(amn, term, bag).promotableInstallmentsCount; var additional_loan_fee_rate = null; if (bag[-23]) { // risk appetite / additional interest rate interest_rate = parseFloat(interest_rate) + parseFloat(bag[-23]); } values.feeRates[51] = interest_rate; var subbag = {}; subbag['first-installment-date'] = bag['first-installment-date']; subbag['loan-amount'] = amn; subbag['loan-term'] = term; subbag['loan-fee'] = parseFloat(values.prices[2]); if (bag[-69]) { var additional_loan_fee_rate_setting = bag[-69]; if (additional_loan_fee_rate_setting.type === 0) { additional_loan_fee_rate = amn * parseFloat(additional_loan_fee_rate_setting.value) / 100; values.feeRates[2] += additional_loan_fee_rate_setting.value; } else { additional_loan_fee_rate = parseFloat(additional_loan_fee_rate_setting.value); } subbag['loan-fee'] = subbag['loan-fee'] + additional_loan_fee_rate; } subbag['enable-fast-transfer-fee'] = bag['enable-fast-transfer-fee'] == undefined ? [] : bag['enable-fast-transfer-fee']; subbag['original-amount'] = bag[-25] == undefined ? 0 : parseFloat(bag[-25]); subbag['additional-payout-date'] = bag['additional-payout-date'] == undefined ? null : bag['additional-payout-date']; subbag['interest-rate'] = interest_rate; subbag['promotable-installments-count'] = _promotable_installments_count; if (bag[-42]) { subbag[-42] = bag[-42]; } if (bag['calculation-date']) { subbag['calculation-date'] = bag['calculation-date']; } var _pre_all_installments = this.evaluateInstallments(subbag, values).schedule; var _all_installments = []; var _all_installments_without_tax = []; values.prices = {}; for (var i = 0, max = _pre_all_installments.length; i < max; i += 1) { var inst = _pre_all_installments[i]; var ext_percent = 0; var ext_amount = 0; if (4 in values.discounts_per) { for (var di = 0; di < values.discounts_per[4].length; di++) { ext_percent += values.discounts_per[4][di].amount; } } if (4 in values.discounts_amn) { for (var di = 0; di < values.discounts_amn[4].length; di++) { ext_percent += values.discounts_amn[4][di].amount; } } var discount = Math.min(inst[4] * ext_percent / 100 + ext_amount, inst[4]); inst.original[4] = inst[4]; inst.discounts[4] = discount; inst.discounted[4] = inst.original[4] - discount; var installment = { date: inst.date, payment: inst.payment, original: { principal: inst.original[1], interest: inst.original[51], commission: inst.original[2], }, principal: inst.discounted[1], interest: inst.discounted[51], commission: inst.discounted[2] }; var installment_without_tax = { date: inst.date, payment: inst.payment, original: { principal: inst.original[1] / (1 + (this.pricelists[1] && this.pricelists[1].tax_percentage ? parseFloat(this.pricelists[1].tax_percentage) : 0)), interest: inst.original[51] / (1 + (this.pricelists[-51] && this.pricelists[-51].tax_percentage ? parseFloat(this.pricelists[-51].tax_percentage) : 0)), commission: inst.original[2] / (1 + (this.pricelists[2] && this.pricelists[2].tax_percentage ? parseFloat(this.pricelists[2].tax_percentage) : 0)) }, principal: inst.discounted[1] / (1 + (this.pricelists[1] && this.pricelists[1].tax_percentage ? parseFloat(this.pricelists[1].tax_percentage) : 0)), interest: inst.discounted[51] / (1 + (this.pricelists[-51] && this.pricelists[-51].tax_percentage ? parseFloat(this.pricelists[-51].tax_percentage) : 0)), commission: inst.discounted[2] / (1 + (this.pricelists[2] && this.pricelists[2].tax_percentage ? parseFloat(this.pricelists[2].tax_percentage) : 0)) }; installment_without_tax.payment = installment_without_tax.principal + installment_without_tax.interest + installment_without_tax.commission; _all_installments.push(installment); _all_installments_without_tax.push(installment_without_tax); for (var id in inst.original) { if (!isNaN(id)) { if (!(id in values.discounted)) { values.discounted[id] = 0; } values.discounted[id] += inst.discounted[id]; if (!(id in values.prices)) { values.prices[id] = 0; } values.prices[id] += inst.original[id]; if (!(id in values.discounts)) { values.discounts[id] = 0; } values.discounts[id] += inst.discounts[id]; } } } var loan_total = values.discounted[1] + values.discounted[2] + values.discounted[51]; for (var id in values.prices) { if (id < 0) { continue; } var name = ''; if (id in this.pricelists) { name = this.pricelists[id].type; } else if (id == 51) { name = 'interest-fee'; } else if (id == 2) { name = 'loan-fee'; } details2.original[name] = values.prices[id]; details2.discount[name] = values.discounts[id]; details2.final[name] = values.discounted[id]; details2.without_tax.original[name] = values.prices_without_tax[id] || values.prices[id]; details2.without_tax.discount[name] = values.discounts_without_tax[id] || values.discounts[id]; details2.without_tax.final[name] = values.discounted_without_tax[id] || values.discounted[id]; if (id in this.pricelists) { details2.tax_percentage[name] = parseFloat(this.pricelists[id].tax_percentage || 0); details2.without_tax.original[name] = values.prices_without_tax[id] || values.prices[id]; details2.without_tax.discount[name] = values.discounts_without_tax[id] || values.discounts[id]; details2.without_tax.final[name] = values.discounted_without_tax[id] || values.discounted[id]; } else { var interest_tax_percantage = parseFloat(0.000); details2.tax_percentage[name] = parseFloat(interest_tax_percantage || 0); details2.without_tax.original[name] = parseFloat(values.prices[id] / (1 + interest_tax_percantage)).toFixed(2); details2.without_tax.discount[name] = parseFloat(values.discounts[id] / (1 + interest_tax_percantage)).toFixed(2); details2.without_tax.final[name] = parseFloat(values.discounted[id] / (1 + interest_tax_percantage)).toFixed(2); } } if ((bag[-15] || false) == false) { delete details2.without_tax; delete details2.tax_percentage; } var ret = { 'loan-amount': bag[-3], 'loan-term': bag[-2], 'loan-repay-amount': values.discounted[1], 'loan-total': loan_total, 'loan-free-extension': values.total_extension_term, 'annual-loan-fee-rate': (values.feeRates[2]/ 100).toFixed(10), 'loan-promotable-installments-count': _promotable_installments_count, details: details2, installments: _all_installments, installments_without_tax: _all_installments_without_tax, 'installment-interest-rate': interest_rate, 'loan-duedate': _all_installments[_all_installments.length - 1].date, }; var total_fee_cost_values = 0; if (values.prices['2']) { ret['loan-fees'] = values.discounted[2]; ret['loan-original-fees'] = values.prices[2]; total_fee_cost_values += values.discounted[2]; } if (values.prices['51']) { ret['loan-interest-fees'] = values.discounted['51']; ret['loan-original-interest-fees'] = values.prices['51']; ret['loan-interest-fee-type-id'] = 51; total_fee_cost_values += values.discounted[51]; } ret['loan-total-fee-cost'] = total_fee_cost_values; if (values.customer_data) { ret['customer-data'] = values.customer_data; } if (values.feeRates) { ret['fee-rates'] = values.feeRates; } if (apr == true) { var daysInYear = 365; const installmentsForApr = JSON.parse(JSON.stringify(((bag[-15] || false) == false) ? _all_installments : _all_installments_without_tax)); if (excludeFeesFromApr.length > 0) { for (var ifa = 0; ifa < installmentsForApr.length; ifa++) { for (var ftei = 0; ftei < excludeFeesFromApr.length; ftei++) { if (installmentsForApr[ifa][excludeFeesFromApr[ftei]] != undefined) { installmentsForApr[ifa].payment = installmentsForApr[ifa].payment - installmentsForApr[ifa][excludeFeesFromApr[ftei]]; } } } } var forcePayoutDate = bag["calculation-date"] ? bag["calculation-date"] : bag[-16] ? bag[-16] : null; ret['loan-apr'] = this.XIRR(parseFloat(bag[-3]), installmentsForApr, null, forcePayoutDate, daysInYear); if (interest_rate) { ret['loan-rpy'] = this.rpyForInstallment(interest_rate); ret['loan-rpm'] = this.rpmForInstallment(interest_rate); ret['loan-rpd'] = this.rpdForInstallment(interest_rate, daysInYear); } } return ret; }, fields: { 460: 'Status', 799: 'Loan count', 802: 'Delay', 1217: 'Id', 2438: 'Is First Loan', 2538: 'Verification Mode', 2788: 'Open principal', 3141: 'Product', 3251: 'Has Open Payday Loan', 3252: 'Has Open Creditline', 3253: 'Has Open Installment Loan', 3256: 'Next installment remaining debt', 3353: 'Installment Delay', 4102: 'Late installment remaining debt (w/o LF)', 6054: 'Last Instantor Succesful Verification', 7560: 'is_force_settled', }, dateValidationDefinition: { evaluate: function (bag) { var control = { canceled: false, quit: false }; (function () { bag["isValid"](); })(); return control; }, freshBag: function (bag, date_to_check) { var n = { date_to_check: date_to_check, holidays: [], valid: false, confirmDate: function (checkDate) { var resultDate = null; if (checkDate === null) { checkDate = "1900-01-01"; } // Check if it is a correct Date object if (checkDate instanceof Date && !isNaN(checkDate.getMonth())) { resultDate = checkDate; } if (typeof checkDate === 'string') { resultDate = new Date(checkDate); // Check if it is a correct date if (isNaN(resultDate.getMonth())) { resultDate = new Date("1900-01-01"); } } if (resultDate === null) { resultDate = new Date("1900-01-01"); } resultDate = new Date(this.getDateToString(resultDate)); resultDate.setMinutes(resultDate.getMinutes() + resultDate.getTimezoneOffset()); return resultDate; }, getDateToString: function (date) { return date.getFullYear() + '-' + ("0" + (date.getMonth() + 1 )).slice(-2) + '-' + ("0" + date.getDate()).slice(-2); }, getValidDateToString: function () { if (!this.valid) { return null; } var date = this.confirmDate(this.date_to_check); return this.getDateToString(date); }, getDay: function () { var date = this.confirmDate(this.date_to_check); return date.getDate(); }, getMonth: function () { var date = this.confirmDate(this.date_to_check); // date.getMonth is 0-indexed return (date.getMonth() + 1); }, getYear: function () { var date = this.confirmDate(this.date_to_check); return date.getFullYear(); }, getDayOfWeek: function () { var date = this.confirmDate(this.date_to_check); return date.getDay(); }, daysInCurrentMonth: function () { var date = this.confirmDate(new Date()); return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(); }, isHoliday: function () { var date = this.confirmDate(this.date_to_check); for(var i = 0; i < this.holidays.length; ++i) { holiday = this.confirmDate(this.holidays[i]); if (Date.parse(date) === Date.parse(holiday)) { return true; } } return false; }, daysFromNow: function () { var now = this.confirmDate(new Date()); var dateToCheck = this.confirmDate(this.date_to_check); var diff = Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()) - Date.UTC(dateToCheck.getFullYear(), dateToCheck.getMonth(), dateToCheck.getDate()); return (Math.floor(diff / (24 * 60 * 60 * 1000)) * -1); }, isValid: function () { this.valid = true; } }; for (var id in bag) { if (!(id in n)) { n[id] = bag[id]; } } return n; }, getRange: function (wished_range) { var max_range = 50; if (wished_range === null || wished_range > max_range || wished_range < 1) { return max_range; } return wished_range; }, getOffset: function (wished_offset) { var min_offset = 0; if (wished_offset === null || wished_offset < min_offset) { return min_offset; } return wished_offset; }, getValidDates: function (bag, offset, range) { range = this.getRange(range); var date = new Date(); date.setDate(date.getDate() + parseInt(this.getOffset(offset))); var validDays = []; for (var i = 0; i < range; i++) { var _date = new Date(date); _date.setDate(_date.getDate() + i); var ibag = this.freshBag(bag, _date); this.evaluate(ibag); if (ibag.valid) { validDays.push(ibag.getValidDateToString()); } } return validDays; }, }, }, creditline: { pricelists: { '1': { type: 'principal', fee_type_id: '1', tax_percentage: '0.000', data: {}, dimension: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if (true) { bag['setAmountRange'](50, 2000, 5); if (control.canceled) return; bag['setTermRange'](48, 48, 1); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, price: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if (true) { vars['amount'] = bag['getAmount'](); bag['setPrice'](vars['amount']); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, buildDimension: function (bag = {}) { if (!this.amounts) { var amounts = []; var terms = []; bag = Object.assign({ setAmountRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (amounts.indexOf(i) === -1) { amounts.push(i); } } }, setTermRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (terms.indexOf(i) === -1) { terms.push(i); } } } }, bag); this.dimension.evaluate(bag); amounts.sort(function (a, b) { return a - b; }); terms.sort(function (a, b) { return a - b; }); this.amounts = amounts; this.terms = terms; } return { amounts: this.amounts, terms: this.terms }; }, buildPrice: function (amount, term, pricelist_bag) { var price = null; var rate = 0; var pricebag = pricelist_bag || {}; pricebag.getAmount = function () { return parseFloat(amount); }; pricebag.getTerm = function () { return parseFloat(term); }; pricebag.setPrice = function (data) { price = data; }; pricebag.setRate = function (data) { rate = data; }; pricebag.parseFloat = parseFloat; this.price.evaluate(pricebag); return { price: parseFloat(price).toFixed(2), rate: parseFloat(rate).toFixed(10) }; } }, '4': { type: 'extension-fee', fee_type_id: '4', tax_percentage: '0.000', data: {}, dimension: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if (true) { bag['setAmountRange'](100, 1000, 5); bag['setTermRange'](1, 1, 1); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, price: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: CRL extension price definition (function () { // Group: Open and InExtension if (([1,3].indexOf(parseInt(bag[460])) !== -1 && bag[5320] >= 1)) { vars['price'] = (bag[3256] * 0.3); bag['setPrice'](vars['price']); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Frozen and Late if (([17,4].indexOf(parseInt(bag[460])) !== -1 && bag[5320] >= 1)) { vars['price'] = (bag[4102] * 0.3); bag['setPrice'](vars['price']); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (([1,3].indexOf(parseInt(bag[460])) !== -1 && bag[5320] < 1)) { vars['price'] = (bag[3256] * 0.3); bag['setPrice'](vars['price']); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (([17,4].indexOf(parseInt(bag[460])) !== -1 && bag[5320] < 1)) { vars['price'] = (bag[4102] * 0.3); bag['setPrice'](vars['price']); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, buildDimension: function (bag = {}) { if (!this.amounts) { var amounts = []; var terms = []; bag = Object.assign({ setAmountRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (amounts.indexOf(i) === -1) { amounts.push(i); } } }, setTermRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (terms.indexOf(i) === -1) { terms.push(i); } } } }, bag); this.dimension.evaluate(bag); amounts.sort(function (a, b) { return a - b; }); terms.sort(function (a, b) { return a - b; }); this.amounts = amounts; this.terms = terms; } return { amounts: this.amounts, terms: this.terms }; }, buildPrice: function (amount, term, pricelist_bag) { var price = null; var rate = 0; var pricebag = pricelist_bag || {}; pricebag.getAmount = function () { return parseFloat(amount); }; pricebag.getTerm = function () { return parseFloat(term); }; pricebag.setPrice = function (data) { price = data; }; pricebag.setRate = function (data) { rate = data; }; pricebag.parseFloat = parseFloat; this.price.evaluate(pricebag); return { price: parseFloat(price).toFixed(2), rate: parseFloat(rate).toFixed(10) }; } }, }, fee_types: { 1: 'principal', 2: 'loan_fee', 3: 'late_fee', 4: 'extension_fee', 5: 'penalty', 41: 'receivable_extension_fee', 51: 'interest_fee', 69: 'payout_fee', 85: 'cash_fee', 168: 'registration_fee', 257: 'late_fee_delay', 259: 'late_fee_delay', 261: 'late_fee_delay', 335: 'court_fee', 360: 'sale_fee', 461: 'late_fee_delay', 466: 'court_fee', }, promotions: { }, loanlimit: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if ((bag[799] == 0 && (toDate(bag['6054']).getTime() < (1714206835806-7776000000) || [4].indexOf(parseInt(bag[2538])) === -1))) { bag['setIncomeVerifyLimit'](1); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Income Verify Limit if (bag[799] > 0) { bag['setIncomeVerifyLimit'](1); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (bag[799] == 0) { bag['setVisibleLimit'](2000); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (bag[799] == 1) { bag['setVisibleLimit'](2000); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (bag[799] == 2) { bag['setVisibleLimit'](2000); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (bag[799] >= 3) { bag['setVisibleLimit'](2000); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, freshBagLimit: function (bag) { var n = { _available_limit: null, _day_lower_bound: null, _visible_limit: null, _day_limit: null, _available_day_limit: null, _lowerbound: null, _income_verify_limit: null, _reject_message: null, _slider_default: null, setSliderDefault: function (amount, term, product) { if (Number.isInteger(amount) && Number.isInteger(term) && Number.isInteger(product)) { this._slider_default = { "amount" : parseFloat(amount).toFixed(2), "term" : parseFloat(term).toFixed(0), "default_product" : product }; } }, setIncomeVerifyLimit: function (limit) { this._income_verify_limit = limit; }, setLimit: function (limit) { this._visible_limit = limit; }, setVisibleLimit: function (limit) { this._visible_limit = limit; }, setAvailableLimit: function (limit) { this._available_limit = limit; }, setHardLimit: function (limit) { this._available_limit = limit; }, getRegistrationField: function (field) { return this[field] || 0; }, getAmount: function () { return bag[-3]; }, getMaximumRepayableAmount: function () { return bag[-22]; }, setDayLowerBound: function (amount) { this._day_lower_bound = amount; }, setDayLimit: function (limit) { this._day_limit = limit; }, setAvailableDayLimit: function (limit) { this._available_day_limit = limit; }, setInstallmentsCount: function (limit) { this._day_limit = limit; }, getInstallmentsCount: function (limit) { return this._day_limit; }, setRejectLoan: function (message) { this._reject_message = message; }, setExtensionLimit: function (limit) { this._extension_limit = limit; }, setLowerBound: function (limit) { this._lowerbound = limit; }, getMonthlyPayment: function (initialPrincipal, annualInterestRate, term) { var annualInterestRate = annualInterestRate / 100; var monthlyInterestRate = annualInterestRate / 12; var divident = initialPrincipal * monthlyInterestRate; var divisor = 1 - (1 / Math.pow((1 + monthlyInterestRate), term)); return divident / divisor; }, getOverpaymentCoefficient: function (annualInterestRate, term) { var initialPrincipal = 1000; var monthlyPayment = this.getMonthlyPayment(initialPrincipal, annualInterestRate, term); var totalRepayableAmount = monthlyPayment * term; return totalRepayableAmount / initialPrincipal; }, getInterestRateApproximationFromAnnuity: function (termMonths) { var termDays = termMonths * 30; var constant = 1.000018; var resultBase = constant + (termDays * 0.0007 + 1) / termMonths; var resultLog = Math.log2(1 + 1 / termMonths); resultBase = Math.pow(resultBase, (1 / resultLog)) - 1; var interestRateApproximationFromAnnuity = ((Math.pow(resultBase, resultLog) - constant) * 12) * 100; var flooredResult = Math.floor(interestRateApproximationFromAnnuity * 100) / 100; return flooredResult; }, calculateTermUpperLimit: function (amount, maxRepayable, interest) { let monthlyInterest = (interest/100) / 12; return (isNaN(Math.ceil(Math.log(1 / (1 - ((amount * monthlyInterest) / maxRepayable))) / Math.log1p(monthlyInterest))) ? 0 : Math.ceil(Math.log(1 / (1 - ((amount * monthlyInterest) / maxRepayable))) / Math.log1p(monthlyInterest))); }, }; for (var id in bag) { if (!(id in n)) { n[id] = bag[id]; } } if ( ! (-8 in n)) { n[-8] = 88; } n["round"] = this.round return n; }, filterAvailableTerms: function (bag, checkFunction) { var limits = this.evaluateLimit(bag); var lowestAvailableTerm = null; for (var index = 0; index < limits.terms.length; index++) { var t = limits.terms[index]; bag['-2'] = t; var currentTermLimits = this.evaluateLimit(bag); if (checkFunction) { if (checkFunction(currentTermLimits)) { lowestAvailableTerm = t; break; } } else if (currentTermLimits.amounts_available.length > 0) { lowestAvailableTerm = t; break; } } return limits.terms.slice(limits.terms.indexOf(lowestAvailableTerm)); }, evaluateLimit: function (bag) { var finalAmounts_available = []; var finalAmounts_visible = []; var finalDays = []; var finalDays_available = []; var finalExtDays = []; var ibag = this.freshBagLimit(bag); var result = this.loanlimit.evaluate(ibag); this.pricelists[1].buildDimension(bag); this.pricelists[4].buildDimension(bag); for (var i = 0; i < this.pricelists[1].amounts.length; i++) { var amn = this.pricelists[1].amounts[i]; if ((ibag._available_limit == null || parseFloat(amn) <= ibag._available_limit) && (ibag._lowerbound == null || parseFloat(amn) >= ibag._lowerbound)) { finalAmounts_available.push(parseFloat(amn).toFixed(2)); } if ((ibag._visible_limit == null || parseFloat(amn) <= ibag._visible_limit) && (ibag._lowerbound == null || parseFloat(amn) >= ibag._lowerbound)) { finalAmounts_visible.push(parseFloat(amn).toFixed(2)); } } for (var i = 0; i < this.pricelists[1].terms.length; i++) { var day = this.pricelists[1].terms[i]; if ((ibag._day_limit == null || parseFloat(day) <= ibag._day_limit) && (ibag._day_lower_bound == null || parseFloat(day) >= ibag._day_lower_bound)) { finalDays.push(parseFloat(day).toFixed(0)); } if ((ibag._available_day_limit == null || parseFloat(day) <= ibag._available_day_limit) && (ibag._day_lower_bound == null || parseFloat(day) >= ibag._day_lower_bound)) { finalDays_available.push(parseFloat(day).toFixed(0)); } } for (var i = 0; i < this.pricelists[4].terms.length; i++) { var day = this.pricelists[4].terms[i]; if (ibag._extension_limit == null || parseFloat(day) <= ibag._extension_limit) { finalExtDays.push(parseFloat(day).toFixed(0)) } } return { 'pricelist-amount-limit': ibag._visible_limit, 'pricelist-amount-hard-limit': ibag._available_limit, 'pricelist-amount-lower-bound': ibag._lowerbound, 'pricelist-day-limit': ibag._day_limit, 'pricelist-available-day-limit': ibag._available_day_limit, 'pricelist-income-verify-limit': ibag._income_verify_limit, 'pricelist-day-lower-bound': ibag._day_lower_bound, 'reject_message': ibag._reject_message, amounts_available: finalAmounts_available, amounts_visible: finalAmounts_visible, terms: finalDays, terms_available: finalDays_available, extterms: finalExtDays, slider_default: ibag._slider_default } }, prolongPermissionRules: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Prohibit prolonging If all products open (function () { // Group: Group if ((bag[3251] == 1 && (bag[3252] == 1 && bag['3253'] == 1))) { bag['prohibitProlong']('Has all products open'); bag['prohibitProlongToInstallment']('Has all products open'); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: OLD VERSION OF PROLONGING=>HAS OPEN PD PROLONG TO CRL (function () { // Group: PD --> CRL FL BEFORE DUEDATE if (([1,3,4].indexOf(parseInt(bag[460])) !== -1 && ((((bag[802] < 31 && bag[2788] >= 50) && [1].indexOf(bag[2438] ? 1 : 0) !== -1) && bag[3251] == 1) && bag[3252] == 0))) { bag['prohibitProlong'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: PD --> CRL FL AFTER DUEDATE if (([1,3,4].indexOf(parseInt(bag[460])) !== -1 && (((((bag[802] > 0 && bag[802] < 31) && bag[2788] >= 50) && [1].indexOf(bag[2438] ? 1 : 0) !== -1) && bag[3251] == 1) && bag[3252] == 0))) { bag['prohibitProlong'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: PD --> CRL CL BEFORE DUEDATE if (([1,3,4].indexOf(parseInt(bag[460])) !== -1 && ((((bag[802] < 31 && bag[3252] == 0) && bag[2788] >= 50) && [0].indexOf(bag[2438] ? 1 : 0) !== -1) && bag[3251] == 1))) { bag['prohibitProlong'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: NEW VERSION OF PROLONGING to IL (function () { // Group: PDL if ((bag['3141'] == 1 && ([1,3,4].indexOf(parseInt(bag['460'])) !== -1 && (bag['2788'] >= 50 && bag[802] < 31)))) { bag['prohibitProlongToInstallment'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: NEW VERSION OF PROLONGING IL -> IL (function () { // Group: IL if ((bag['3141'] == 2 && ([1].indexOf(parseInt(bag[460])) !== -1 && (bag['2788'] >= 50 && bag[802] < 31)))) { bag['prohibitProlongToInstallment'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: NEW VERSION OF PROLONGING - TO CRL -> IL (function () { // Group: CRL if ((bag['3141'] == 3 && ([17,1,4].indexOf(parseInt(bag[460])) !== -1 && (bag['2788'] >= 50 && bag['3353'] < 31)))) { bag['prohibitProlongToInstallment'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, freshBagProlongPermissionRule: function (bag) { var n = { _loanProlongPermitted: false, _loanProlongPermittedToPayday: false, _loanProlongPermittedToInstallment: false, _loanProlongPermittedToCreditline: false, _errorMessage: null, _errorMessageProlongToPayday: null, _errorMessageProlongToInstallment: null, _errorMessageProlongToCreditline: null, _loanSettingId: null, _feetypes: [], allowProlong: function () { this._loanProlongPermitted = true; this._errorMessage = null; }, allowProlongToPayday: function () { this._loanProlongPermittedToPayday = true; this._errorMessageProlongToPayday = null; }, allowProlongToInstallment: function () { this._loanProlongPermittedToInstallment = true; this._errorMessageProlongToInstallment = null; }, allowProlongToCreditline: function () { this._loanProlongPermittedToCreditline = true; this._errorMessageProlongToCreditline = null; }, prohibitProlong: function (msg) { this._loanProlongPermitted = false; this._errorMessage = msg; }, setLoanSettings: function (id) { this._loanSettingId = id; }, prohibitProlongToPayday: function (msg) { this._loanProlongPermittedToPayday = false; this._errorMessageProlongToPayday = msg; }, prohibitProlongToInstallment: function (msg) { this._loanProlongPermittedToInstallment = false; this._errorMessageProlongToInstallment = msg; }, prohibitProlongToCreditline: function (msg) { this._loanProlongPermittedToCreditline = false; this._errorMessageProlongToCreditline = msg; }, feetypeToNewLoan: function (feetype, percentage, maxvalue) { this._feetypes.push({ "feetype": feetype, "percentage": percentage, "maxvalue": maxvalue }); }, hasLoanOpenInAllLenders: function () { return bag[-33]; }, isRequestForLoanFromPlaton: function () { return bag["is-backend"] || false; }, isRequestForLoanFromClientzone: function () { return !bag["is-backend"]; }, }; for (var id in bag) { if ((typeof bag[id] === 'string') && !isNaN(bag[id]) && isFinite(bag[id]) && typeof bag[id] !== "boolean") { bag[id] = parseFloat(bag[id]); } if (!(id in n)) { n[id] = bag[id]; } } return n; }, evaluateProlongPermisson: function (bag) { var ibag = this.freshBagProlongPermissionRule(bag); var result = this.prolongPermissionRules.evaluate(ibag); return { 'loan-prolong-permitted': ibag._loanProlongPermitted, 'loan-prolong-permitted-to-payday': ibag._loanProlongPermittedToPayday, 'loan-prolong-permitted-to-installment': ibag._loanProlongPermittedToInstallment, 'loan-prolong-permitted-to-creditline': ibag._loanProlongPermittedToCreditline, 'loan-prolong-error': ibag._errorMessage, 'loan-prolong-to-payday-error': ibag._errorMessageProlongToPayday, 'loan-prolong-to-installment-error': ibag._errorMessageProlongToInstallment, 'loan-prolong-to-creditline-error': ibag._errorMessageProlongToCreditline, 'prolong-loan-setting-id': ibag._loanSettingId, 'loan-feetype-mapping': ibag._feetypes } }, evaluateExtensionPromotions: function (now, bag, values) { var ibag = {}; var result = null; var existingpromo = null; var percentpromo = null; var percentpromos = []; var usedPromotions = []; if (bag['existing-promotions']) { var existingPromos = bag['existing-promotions'].sort(function (a, b) { return b.priority - a.priority; }); ibag = this.freshBag(bag, null); for (var i = 0; i < existingPromos.length; i++) { existingpromo = existingPromos[i]; if (existingpromo['type'] == 'percent') { percentpromo = { 'amount': parseFloat(existingpromo['amount']), 'id': existingpromo['promoId'] }; if (existingpromo['installmentIndex'] !== undefined) { // installment index can be 0 and then it wouldnt go in percentpromo['installment_index'] = existingpromo['installmentIndex'] + 1; // + 1 because for promostaging the first installment is index 1 and not 0 } if (!percentpromos[existingpromo['feeTypeId']]) { percentpromos[existingpromo['feeTypeId']] = []; } percentpromos[existingpromo['feeTypeId']].push(percentpromo); usedPromotions.push(existingpromo['promoId'].toString()); } } ibag['discounts_per'] = percentpromos; this.fillDiscounts(ibag, values); } }, extensionPermissionRules: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: SET-3547 Allow ext for all (function () { // Group: Group if (bag['1217'] !== null) { bag['allowExtension'](); bag['exit'](); if (control.canceled) return; } else { bag['allowExtension'](); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: Prohibit extension if force settledate is set (function () { // Group: Group 1 if ((bag['7560'] == 1 && bag['3141'] == 3)) { bag['prohibitExtension']('force settledate set - no extension possible CFIT-3333'); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: Prohibit if early repayment (function () { // Group: Prohibit if early repayment if ([1].indexOf(bag[5266] ? 1 : 0) !== -1) { bag['prohibitExtension']('early settle'); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: Remaining debt < 10 Euro (function () { // Group: Group if ((((bag[4102] > 0 && bag[4102] < 10) || (bag[3256] >= 0 && bag[3256] < 10)) || bag[3353] > 60)) { bag['prohibitExtension']('Fee limit reached'); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: Alow (function () { // Group: Group if (true) { bag['allowExtension'](); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; }, freshBag: function (bag, extensionPrice) { var n = { _loanExtensionPermitted: false, _errorMessage: null, allowExtension: function () { this._loanExtensionPermitted = true; this._errorMessage = null; }, prohibitExtension: function (msg) { this._loanExtensionPermitted = false; this._errorMessage = msg; } }; for (var id in bag) { if ((typeof bag[id] === 'string') && !isNaN(bag[id]) && isFinite(bag[id])) { bag[id] = parseFloat(bag[id]); } if (!(id in n)) { n[id] = bag[id]; } } n[-11] = extensionPrice; return n; } }, evaluateExtension: function (bag) { bag[-3] = bag[-3] || bag['loan-amount'] bag[-2] = bag[-2] || bag['loan-term'] bag[-1] = bag[-1] || bag['loan-extension-term'] var values = { discounts_per: {}, discounts_amn: {}, extensions: {}, total_extension_term: 0, prices: {}, feeRates: {}, discounts: {}, discounted: {} } var that = this; var now = new Date().getTime(); var amn = parseFloat(bag[-3]).toFixed(2); var term = parseFloat(bag[-2]).toFixed(0); var extterm = parseFloat(bag[-1]).toFixed(0); if (bag[-7] && (bag[-7] == '-1' || bag[-7] == '1')) { aleg: for (var id in this.pricelists) { if (!('buildPrice' in this.pricelists[id])) { if (!(amn in this.pricelists[id].data)) { var pamn = '0.0'; for (var iamn in this.pricelists[id].data) { if (parseFloat(iamn) > parseFloat(amn)) { if (bag[-7] == '1') { amn = iamn; break aleg; } else { if (parseFloat(pamn) == 0.0) { throw new Error('There is no smaller amount than ' + amn + ' to round down to for pricelist with id ' + id); } amn = pamn; break aleg; } } pamn = iamn; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '1') { amn = pamn; break aleg; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '-1') { amn = pamn; break aleg; } } } } } for (var id in this.pricelists) { if ( id != 4 ) { continue; } if ('buildPrice' in this.pricelists[id]) { var save = bag['pricelist_bag']; bag['pricelist_bag'] = {}; for (var x in save) { bag['pricelist_bag'][x] = save[x]; } for (var x in bag) { if (x != 'pricelist_bag') { bag['pricelist_bag'][x] = bag[x]; } } var pricelist_bag = {}; for (var item in bag['pricelist_bag']) { pricelist_bag[item] = bag['pricelist_bag'][item]; } var pricelistResult = this.pricelists[id].buildPrice(amn, extterm, pricelist_bag); var price = parseFloat(pricelistResult.price); var feeRate = parseFloat(pricelistResult.rate); values.prices[id] = price; values.feeRates[id] = feeRate; } else { if (!this.pricelists[id].data) continue; if (!(amn in this.pricelists[id].data)) { throw new Error('Invalid Amount ' + amn + ' for pricelist with id ' + id); } if (!extterm in this.pricelists[id].data[amn]) { throw new Error('Invalid Term ' + extterm + ' for pricelist with id ' + id + ' for amount ' + amn); } values.prices[id] = parseFloat(this.pricelists[id].data[amn][extterm]); values.feeRates[id] = 0; } } if ('existing-fees' in bag) { for (var id in bag['existing-fees']) { if (bag['existing-fees'][id].amount == 0) { continue; } if (!values.prices[id]) { values.prices[id] = 0; } values.prices[id] += bag['existing-fees'][id].amount; } } this.evaluateExtensionPromotions(now, bag, values); var details2 = { 'percent-discounts' : {}, 'amount-discounts' : {}, 'extensions': {}, original: {}, discount: {}, final: {} }; for (var id in values.prices) { var feeType = null; if (id in this.pricelists) { feeType = this.pricelists[id].type; } else if (id in bag['existing-fees']) { feeType = bag['existing-fees'][id].type; } var discountPercentAr = values.discounts_per[id]; var discountPercent = 0; if (discountPercentAr) { details2['percent-discounts'][feeType] = discountPercentAr; for (var i = 0; i < discountPercentAr.length; i++) { discountPercent += parseFloat(discountPercentAr[i].amount); } } var discountAmountAr = values.discounts_amn[id]; var discountAmount = 0; if (discountAmountAr) { details2['amount-discounts'][feeType] = discountAmountAr; for (var i = 0; i < discountAmountAr.length; i++) { discountAmount += parseFloat(discountAmountAr[i].amount); } } var discount = Math.min(values.prices[id] * discountPercent / 100 + discountAmount, values.prices[id]); var finalAmount = values.prices[id] - discount; values.discounts[id] = parseFloat(discount.toFixed(2)); values.discounted[id] = parseFloat(finalAmount.toFixed(2)); details2.original[feeType] = values.prices[id]; details2.discount[feeType] = values.discounts[id]; details2.final[feeType] = values.discounted[id]; } var ibag = null; var extensionPrice = values.discounted[4]; ibag = this.extensionPermissionRules.freshBag(bag, extensionPrice); this.extensionPermissionRules.evaluate(ibag); var calc_loan_duedate = bag['loan_duedate'] ? new Date(Date.parse(bag['loan_duedate'])) : null; if (calc_loan_duedate) { var calc_loan_is_payday = bag['loan_is_payday']; var calc_extension_permitted = ibag == null || (!ibag._errorMessage && ibag._loanExtensionPermitted); var calc_term = parseInt(extterm); var calc_duedate = null; var calc_now = new Date(); var calc_late = calc_loan_duedate < calc_now; var calc_actDuedate = calc_late ? calc_now : calc_loan_duedate; if (calc_extension_permitted) { calc_duedate = calc_actDuedate; if (calc_loan_is_payday) { calc_duedate.setDate(calc_duedate.getDate() + calc_term); } else { calc_duedate.setMonth(calc_duedate.getMonth() + calc_term); } calc_duedate = (calc_duedate.toISOString()).substr(0, 10); } } return { 'loan-amount': bag[-3], 'loan-term': bag[-2], 'loan-extension-term': bag[-1], 'loan-extension-fees': values.discounted[4], 'loan-extension-duedate': calc_duedate, 'loan-extension-permitted': ibag._loanExtensionPermitted, 'loan-extension-error': ibag._errorMessage, 'loan-original-extension-fees': values.prices[4], 'loan-free-extension': values.total_extension_term, details: details2, }; }, evaluateInstallments: function (bag, promotions) { function daysBetween(t1, t2) { var oneDay = 24 * 60 * 60 * 1000; return Math.round(Math.abs((t1.getTime() - t2.getTime())/oneDay)); } function dateWithoutTime(date) { var newdate = date ? new Date(date) : new Date(); newdate.setMinutes(0); newdate.setHours(0); newdate.setSeconds(0); return newdate; } function getIntervalJson(interval) { var yearsSplit = interval.split('y'); var monthsSplit = yearsSplit[1].split('m'); var daysSplit = monthsSplit[1].split('d'); return { years: parseInt(yearsSplit[0]), months: parseInt(monthsSplit[0]), days: parseInt(daysSplit[0]) }; } function getIntervalNewDate(paymentDate, interval) { var intervalJson = getIntervalJson(interval); var intervalNewDate = new Date(paymentDate); intervalNewDate.setFullYear(paymentDate.getFullYear() + intervalJson.years); intervalNewDate.setMonth(paymentDate.getMonth() + intervalJson.months); intervalNewDate.setDate(paymentDate.getDate() + intervalJson.days); return intervalNewDate; } function getMonthlyPaymentDate(date, bag) { if (!bag || !bag['grace-period-days']) { return date; } var monthlyPaymentDate = new Date(date); monthlyPaymentDate.setDate(date.getDate() + parseInt(bag['grace-period-days'])); return monthlyPaymentDate; } function getNextPaymentDate(paymentDate, targetDay, bag) { if (bag && 'use-interval' in bag && bag['use-interval']) { return getIntervalNewDate(paymentDate, bag['interval']); } var followingMonth, followingYear, lastOfFollowingMonth, newDate; if (paymentDate.getMonth() === 11) { followingMonth = 0; followingYear = paymentDate.getFullYear() + 1; } else { followingMonth = paymentDate.getMonth() + 1; followingYear = paymentDate.getFullYear(); } lastOfFollowingMonth = new Date(followingYear, followingMonth + 1, 0); newDate = dateWithoutTime(paymentDate); if(lastOfFollowingMonth.getDate() < targetDay) { newDate.setMonth(lastOfFollowingMonth.getMonth()); newDate.setDate(0); } else { newDate.setMonth(paymentDate.getMonth() + 1); newDate.setDate(targetDay); } return newDate; } function calcPromotionDiscount(feeAmount, feeTypeId, currentInstallmentIndex, promotions) { var totalReduc = 0; if (promotions.discounts_per[feeTypeId]) { var promos = promotions.discounts_per[feeTypeId]; for (var i = 0; i < promos.length; i++) { var p = promos[i]; var a = (p.amount / 100) * feeAmount; if (p.installment_index - 1 === currentInstallmentIndex) { totalReduc += a; } else if (p.installment_index === undefined) { totalReduc += a; } } } if (promotions.discounts_amn[feeTypeId]) { var promos = promotions.discounts_amn[feeTypeId]; for (var z = 0; z < promos.length; z++) { var p = promos[z]; if (! ('used' in p)) { p.used = 0; } var a = Math.min(p.amount - p.used, feeAmount - totalReduc); if (p.installment_index - 1 === currentInstallmentIndex) { totalReduc += a; } else if (p.installment_index === undefined) { totalReduc += a; } p.used += a; }; } return Math.max(0, (feeAmount - totalReduc)); } var amount = parseFloat(bag['loan-amount']); var term = parseFloat(bag['loan-term']); var commission_rate = parseFloat(bag['creditline-percent-creditline']) / 100 / 360; var fallback_rate = parseFloat(bag['creditline-percent-creditline-fallback']) / 100 / 360; var principal_repay_rate = bag['creditline-percent-principal-repay']; var interest_rate = parseFloat(bag['interest-rate']) / 100 / 360; var interest_rate_full = parseFloat(bag['interest-rate']); var min_repay_amount = parseFloat(bag['creditline-min-monthly-payment']); var use_equal_principal_distribution = bag['use-equal-principal-distribution']; var frontend_calculate_sample_term = bag['frontend-calculate-sample-term']; var now = bag['loan-issue-date']; var paymentDate = dateWithoutTime(now); var oldDate = dateWithoutTime(now); var sampleTermDate = dateWithoutTime(now); var schedule = []; var remaining_amount = amount; var commission_carry_over = 0; var interest_carry_over = 0; var repayment; var recalc3 = 0; if (bag['-42']) { bag['-42'].forEach(function (version) { if (version.product_id == 3) { recalc3 = version.recalc_version; } }); } // adapt repayment interval if (bag['first-installment-date']) { paymentDate = dateWithoutTime(bag['first-installment-date']); } else { paymentDate = getNextPaymentDate(paymentDate, paymentDate.getDate(), bag); } // set sample term date if (frontend_calculate_sample_term && frontend_calculate_sample_term != '0y0m0d') { sampleTermDate = getIntervalNewDate(sampleTermDate, frontend_calculate_sample_term); } else { sampleTermDate = null; } var target_day = paymentDate.getDate(); for (var i = 0; i < term; i += 1) { if (i == (term - 1) && sampleTermDate !== null) { if (sampleTermDate > paymentDate) { term++; } else { paymentDate = sampleTermDate; } } var days = daysBetween(oldDate, paymentDate), fallback = Math.floor((fallback_rate * amount * days) * 100) / 100, interest = Math.floor((interest_rate * remaining_amount * days) * 100) / 100, commission = Math.floor((commission_rate * amount * days) * 100) / 100, principal = use_equal_principal_distribution ? Math.floor((amount / term) * 100) / 100 : Math.floor(principal_repay_rate * remaining_amount) / 100, total_payment, old_year_days, new_year_days, schedule_entry; if (recalc3 > 3) { if (paymentDate.getFullYear() > oldDate.getFullYear()) { old_year_days = daysBetween(new Date(oldDate.getFullYear(), 0, 1), new Date(oldDate.getFullYear() + 1, 0, 1)); new_year_days = daysBetween(new Date(paymentDate.getFullYear(), 0, 1), new Date(paymentDate.getFullYear() + 1, 0, 1)); var installment_days_in_old_year = daysBetween(oldDate, new Date(oldDate.getFullYear() + 1, 0, 1)) + 1, installment_days_in_new_year = daysBetween(new Date(paymentDate.getFullYear(), 0, 1), paymentDate) - 1; interest = Math.floor( ( (remaining_amount * (interest_rate_full / 100 / old_year_days * installment_days_in_old_year )) + (remaining_amount * (interest_rate_full / 100 / new_year_days * installment_days_in_new_year )) ) * 100) / 100; fallback = Math.floor( ( (parseFloat(bag['creditline-percent-creditline-fallback']) / 100 / old_year_days * amount * installment_days_in_old_year ) + (parseFloat(bag['creditline-percent-creditline-fallback']) / 100 / new_year_days * amount * installment_days_in_new_year ) ) * 100) / 100; commission = Math.floor( ( (parseFloat(bag['creditline-percent-creditline']) / 100 / old_year_days * amount * installment_days_in_old_year ) + (parseFloat(bag['creditline-percent-creditline']) / 100 / new_year_days * amount * installment_days_in_new_year ) ) * 100) / 100; } else { old_year_days = daysBetween(new Date(oldDate.getFullYear(), 0, 1), new Date(oldDate.getFullYear() + 1, 0, 1)); interest = Math.floor(remaining_amount * (interest_rate_full / 100 / old_year_days * days) * 100) / 100; fallback = Math.floor(parseFloat(bag['creditline-percent-creditline-fallback']) / 100 / old_year_days * amount * days * 100) / 100; commission = Math.floor(parseFloat(bag['creditline-percent-creditline']) / 100 / old_year_days * amount * days * 100) / 100; } } commission_carry_over += commission - (Math.floor(commission * 100) / 100); interest_carry_over += (interest_rate * remaining_amount * days) - interest; if (recalc3 == 0) { if (commission_carry_over >= 0.01) { commission_carry_over -= 0.01; commission += 0.01; } if (interest_carry_over >= 0.01) { interest_carry_over -= 0.01; interest += 0.01; } } if (fallback > (interest + commission)) { commission = fallback; interest = 0; } total_payment = commission + interest + principal; if (total_payment < min_repay_amount) { principal = Math.min(principal + (min_repay_amount - total_payment), remaining_amount); } else if (i == term - 1) { principal = remaining_amount; } if (interest > 0 && bag['additional-interest-per-installment'] && !isNaN(bag['additional-interest-per-installment'])) { interest += parseFloat(bag['additional-interest-per-installment']); } schedule_entry = { date: paymentDate, monthlyPaymentDate: getMonthlyPaymentDate(paymentDate, bag), original: { 1: principal, 2: commission, 51: interest }, discounted: { 1: principal, 2: calcPromotionDiscount(commission, 2, i, promotions), 51: calcPromotionDiscount(interest, 51, i, promotions), }, discounts: {} }; schedule_entry.payment = schedule_entry.discounted[1] + schedule_entry.discounted[2] + schedule_entry.discounted[51]; schedule_entry.discounts[1] = parseFloat(schedule_entry.original[1] - schedule_entry.discounted[1]); schedule_entry.discounts[2] = parseFloat(schedule_entry.original[2] - schedule_entry.discounted[2]); schedule_entry.discounts[51] = parseFloat(schedule_entry.original[51] - schedule_entry.discounted[51]); schedule.push(schedule_entry); oldDate = new Date(paymentDate); paymentDate = getNextPaymentDate(paymentDate, target_day, bag); remaining_amount -= principal; } return { schedule: schedule }; }, calculateAPR: function (startAmount, values) { var PRECISION = 0.00001; var MAX_ATTEMPTS = 1000; var bsMinB = -0.999999999999; var bsMaxB = 2000000000; var principal = startAmount; var attempts = 0; var repaymentTotal = 0; var APRRate = 1; while (Math.abs(repaymentTotal - principal) > PRECISION) { if (attempts >= MAX_ATTEMPTS || (bsMaxB == bsMinB) && (bsMaxB == APRRate)) { return NaN; } attempts++; if (attempts > 1) { if (repaymentTotal < principal) { bsMaxB = APRRate; } else { bsMinB = APRRate; } APRRate = bsMaxB - (bsMaxB - bsMinB) / 2; } repaymentTotal = 0; for (var i = 0; i < values.length; i++) { var rt = Math.pow(1 + APRRate, (i + 1) / 12); // 12 = compounding period repaymentTotal += values[i].payment / rt; } } return APRRate * 100; }, DaysBetween: function(date1, date2) { var oneDay = 24*60*60*1000; return Math.round(Math.abs((date1.getTime() - date2.getTime())/oneDay)); }, XNPV: function(rate, values, daysInYear) { var payment_fee_percentage = 0.00 / 100; var xnpv = 0.0; var firstDate = new Date(values[0].date); for (var i = 0, max = values.length; i < max; i += 1) { var tmp = values[i]; var value; if (tmp.payment < 0) { value = tmp.payment * (1 - payment_fee_percentage); } else { value = tmp.payment * (1 + payment_fee_percentage); } var date = new Date(tmp.date); xnpv += value / Math.pow(1 + rate, this.DaysBetween(firstDate, date)/daysInYear); } return xnpv; }, aprForPayday: function(initialAmount, term, toRepay, daysInYear) { var payment_fee_percentage = 0.00 / 100; return Math.round((Math.pow(toRepay * (1 + payment_fee_percentage) / (initialAmount * (1 - payment_fee_percentage)), daysInYear / term) - 1) * 10000) / 100; }, arForPayday: function (initialAmount, term, toRepay, daysInYear) { var price = toRepay - initialAmount; return Math.round(price / initialAmount * (daysInYear / term) * 10000) / 100; }, rpyForPayday: function (initialAmount, term, toRepay, daysInYear) { var price = toRepay - initialAmount; return Math.round((price / initialAmount / term * daysInYear) * 10000) / 100; }, rpmForPayday: function (initialAmount, term, toRepay, daysInYear) { var price = toRepay - initialAmount; return Math.round((price / initialAmount / term * daysInYear / 12) * 10000) / 100; }, rpdForPayday: function (initialAmount, term, toRepay) { var price = toRepay - initialAmount; return Math.round((price / initialAmount / term) * 10000) / 100; }, XIRR: function(initialAmount, values, guess, forcePayoutDate, daysInYear) { if (!guess) guess = 0.1; var payoutDate = forcePayoutDate ? new Date(forcePayoutDate) : new Date(); payoutDate.setMinutes(0); payoutDate.setHours(0); payoutDate.setSeconds(0); values = values.slice(0); values.unshift({payment:-initialAmount, date:payoutDate}); var x1 = 0.0; var x2 = guess; var f1 = this.XNPV(x1, values, daysInYear); var f2 = this.XNPV(x2, values, daysInYear); for (var i = 0; i < 100; i++) { if ((f1 * f2) < 0.0) break; if (Math.abs(f1) < Math.abs(f2)) { f1 = this.XNPV(x1 += 1.6 * (x1 - x2), values, daysInYear); } else { f2 = this.XNPV(x2 += 1.6 * (x2 - x1), values, daysInYear); } }; if ((f1 * f2) > 0.0) return null; var f = this.XNPV(x1, values, daysInYear); if (f < 0.0) { var rtb = x1; var dx = x2 - x1; } else { var rtb = x2; var dx = x1 - x2; }; for (var i = 0; i < 100; i++) { dx *= 0.5; var x_mid = rtb + dx; var f_mid = this.XNPV(x_mid, values, daysInYear); if (f_mid <= 0.0) rtb = x_mid; if ((Math.abs(f_mid) < 1.0e-6) || (Math.abs(dx) < 1.0e-6)) return Math.max(0, x_mid * 100); }; return null; }, rpyForInstallment: function (interestRate) { return interestRate; }, rpmForInstallment: function (interestRate) { return interestRate / 12; }, rpdForInstallment: function (interestRate, daysInYear) { return interestRate / daysInYear; }, // add base functions fillDiscounts: function (ibag, values) { for (var id in ibag.discounts_per) { if (!(id in values.discounts_per)) { values.discounts_per[id] = []; } for (var i = 0; i < ibag.discounts_per[id].length; i++) { values.discounts_per[id].push(ibag.discounts_per[id][i]); } } for (var id in ibag.discounts_amn) { if (!(id in values.discounts_amn)) { values.discounts_amn[id] = []; } for (var i = 0; i < ibag.discounts_amn[id].length; i++) { values.discounts_amn[id].push(ibag.discounts_amn[id][i]); } } if (!('designations' in values)) { values.designations = {}; } for (var promo_id in ibag.designations) { values.designations[promo_id] = ibag.designations[promo_id]; } for (var promo_id in ibag.customer_data) { if (!('customer_data' in values)) { values.customer_data = {}; } values.customer_data[promo_id] = ibag.customer_data[promo_id]; } var totalTerm = 0; for (var i = 0; i < ibag.extensions.length; i++) { var promo_id = ibag.extensions[i].id; if (!(promo_id in values.extensions)) { values.extensions[promo_id] = 0; } values.extensions[promo_id] += ibag.extensions[i].term; values.total_extension_term += ibag.extensions[i].term; } }, round: function (value, interval, mode) { var returnValue = null; var value = value / interval; switch (mode) { case 0: //FUNCTION_ROUND_FLOOR returnValue = Math.floor(value); break; case 1: //FUNCTION_ROUND_CEIL returnValue = Math.ceil(value); break; case 3: //FUNCTION_ROUND_HALF_DOWN returnValue = -Math.round(-value); break; case 2: //FUNCTION_ROUND_HALF_UP returnValue = Math.round(value); break; } return returnValue ? returnValue / (1 / interval) : returnValue; }, freshBag: function (bag, promo_id) { var that = this; var n = { discounts_per: {}, discounts_amn: {}, extensions: [], designations: {}, customer_data: {}, addInstallmentPromotionPercent: function (feetype, amount, installment_index) { if (!(feetype in this.discounts_per)) { this.discounts_per[feetype] = []; } this.discounts_per[feetype].push({ amount: amount, id: promo_id, installment_index: installment_index }); }, addInstallmentPromotion: function (feetype, amount, installment_index) { if (!(feetype in this.discounts_amn)) { this.discounts_amn[feetype] = []; } this.discounts_amn[feetype].push({ amount: amount, id: promo_id, installment_index: installment_index }); }, addDiscountPercent: function (feetype, amount) { if (!(feetype in this.discounts_per)) { this.discounts_per[feetype] = []; } this.discounts_per[feetype].push({ amount: amount, id: promo_id }); }, addDiscount: function (feetype, amount) { if (!(feetype in this.discounts_amn)) { this.discounts_amn[feetype] = []; } this.discounts_amn[feetype].push({ amount: amount, id: promo_id }); }, setDesignation: function (designation) { this.designations[promo_id] = designation; }, addFreeExtension: function (term) { this.extensions.push({ term: term, id: promo_id }); }, getCustomerData: function (type) { if ('customer-data' in bag && type in bag['customer-data']) { return bag['customer-data'][type]; } else { return null; } }, setCustomerData: function (type, data) { if (!(promo_id in this.customer_data)) { this.customer_data[promo_id] = []; } this.customer_data[promo_id].push({ type: type, data: data }); }, round: that.round, }; for (var id in bag) { if (!(id in n)) { n[id] = bag[id]; } } return n; }, evaluateLoanPromotions: function (now, bag, values) { var ibag = {}; var existingpromo = null; var percentpromo = null; var percentpromos = []; var usedPromotions = []; if (bag['existing-promotions']) { var existingPromos = bag['existing-promotions'].sort(function (a, b) { return b.priority - a.priority; }); ibag = this.freshBag(bag, null); for (var i = 0; i < existingPromos.length; i++) { existingpromo = existingPromos[i]; if (existingpromo['type'] == 'percent') { percentpromo = { 'amount': parseFloat(existingpromo['amount']), 'id': existingpromo['promoId'] }; if (existingpromo['installmentIndex'] !== undefined) { // installment index can be 0 and then it wouldnt go in percentpromo['installment_index'] = existingpromo['installmentIndex'] + 1; // + 1 because for promostaging the first installment is index 1 and not 0 } if (!percentpromos[existingpromo['feeTypeId']]) { percentpromos[existingpromo['feeTypeId']] = []; } percentpromos[existingpromo['feeTypeId']].push(percentpromo); usedPromotions.push(existingpromo['promoId'].toString()); } } ibag['discounts_per'] = percentpromos; this.fillDiscounts(ibag, values); } var quit = false; }, addPromotionResult: function (now, bag, values, start, end, id) { var ibag = {}; var result = null; if (start < now && now < end) { ibag = this.freshBag(bag, id); result = this.promotions[id].evaluate(ibag); this.fillDiscounts(ibag, values); return result.quit; } return false; }, evaluate: function (bag) { bag[-3] = bag[-3] || bag['loan-amount']; bag[-2] = bag[-2] || bag['loan-term']; var values = { discounts_per: {}, discounts_amn: {}, extensions: {}, total_extension_term: 0, prices: {}, feeRates: {}, discounts: {}, discounted: {}, prices_without_tax: {}, discounted_without_tax: {}, discounts_without_tax: {} }; var that = this; var now = new Date().getTime(); var amn = parseFloat(bag[-3]).toFixed(2); var term = parseFloat(bag[-2]).toFixed(0); var extterm = bag[-1] == undefined ? term : parseFloat(bag[-1]).toFixed(0); // apr calculation is by default true, unless apr is set var apr = bag[-13] == undefined ? true : bag[-13]; if (bag[-7] && (bag[-7] == '-1' || bag[-7] == '1')) { aleg: for (var id in this.pricelists) { if (!('buildPrice' in this.pricelists[id])) { if (!(amn in this.pricelists[id].data)) { var pamn = '0.0'; for (var iamn in this.pricelists[id].data) { if (parseFloat(iamn) > parseFloat(amn)) { if (bag[-7] == '1') { amn = iamn; break aleg; } else { if (parseFloat(pamn) == 0.0) { throw new Error('There is no smaller amount than ' + amn + ' to round down to for pricelist with id ' + id); } amn = pamn; break aleg; } } pamn = iamn; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '1') { amn = pamn; break aleg; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '-1') { amn = pamn; break aleg; } } } } } for (var id in this.pricelists) { if ('buildPrice' in this.pricelists[id]) { bag['pricelist_bag'] = bag['pricelist_bag'] || {}; for (var x in bag) { if (x != 'pricelist_bag') { bag['pricelist_bag'][x] = bag[x]; } } var pricelistResult = this.pricelists[id].buildPrice(amn, term, bag['pricelist_bag']); values.prices[id] = pricelistResult.price; values.feeRates[id] = pricelistResult.rate; } else { if (!(amn in this.pricelists[id].data)) { throw new Error('Invalid Amount ' + amn + ' for pricelist with id ' + id); } if (!term in this.pricelists[id].data[amn]) { throw new Error('Invalid Term ' + term + ' for pricelist with id ' + id + ' for amount ' + amn); } values.prices[id] = this.pricelists[id].data[amn][term]; values.feeRates[id] = 0; } if (this.pricelists[id].tax_percentage && this.pricelists[id].tax_percentage > 0) { values.prices_without_tax[id] = (values.prices[id] / (1 + parseFloat(this.pricelists[id].tax_percentage))).toFixed(2); } } var interest_rate = 48.00; values.feeRates[51] = interest_rate; values.feeRates[2] = 0.00; this.evaluateLoanPromotions(now, bag, values); var details2 = { 'percent-discounts': {}, 'amount-discounts': {}, extensions: {}, original: {}, discount: {}, final: {}, tax_percentage: {}, without_tax: { original: {}, final: {}, discount: {} } }; var subbag = {}; subbag['additional-interest-per-installment'] = bag['additional-interest-per-installment']; subbag['first-installment-date'] = bag['first-installment-date']; subbag['loan-amount'] = amn; subbag['loan-term'] = term; subbag['loan-fee'] = values.prices[2]; subbag['creditline-percent-creditline'] = 0.00; subbag['creditline-percent-creditline-fallback'] = 0.00; subbag['creditline-percent-principal-repay'] = 180.00; subbag['creditline-percent-principal'] = 48.00; subbag['creditline-min-monthly-payment'] = 0.00; subbag['use-equal-principal-distribution'] = true; subbag['frontend-calculate-sample-term'] = bag[-43] ? '0y0m0d' : null; subbag['loan-issue-date'] = bag[-16] ? new Date(bag[-16]) : new Date(); if (bag['calculation-date']) { subbag['loan-issue-date'] = new Date(bag['calculation-date']); } subbag['interval'] = '0y1m0d'; subbag['use-interval'] = false; subbag['interest-rate'] = interest_rate; subbag['grace-period-days'] = ''; if (bag[-42]) { subbag[-42] = bag[-42]; } var _pre_all_installments = this.evaluateInstallments(subbag, values).schedule; var _all_installments = []; var _all_installments_without_tax = []; values.prices = {}; for (var i = 0, max = _pre_all_installments.length; i < max; i += 1) { var inst = _pre_all_installments[i]; var ext_percent = 0; var ext_amount = 0; if (4 in values.discounts_per) { for (var di = 0; di < values.discounts_per[4].length; di++) { ext_percent += values.discounts_per[4][di].amount; } } if (4 in values.discounts_amn) { for (var di = 0; di < values.discounts_amn[4].length; di++) { ext_percent += values.discounts_amn[4][di].amount; } } var discount = Math.min(inst[4] * ext_percent / 100 + ext_amount, inst[4]); inst.original[4] = inst[4]; inst.discounts[4] = discount; inst.discounted[4] = inst.original[4] - discount; var installment = { date: inst.date, monthlyPaymentDate: inst.monthlyPaymentDate, payment: inst.payment, original: { principal: inst.original[1], interest: inst.original[51], commission: inst.original[2], }, principal: inst.discounted[1], interest: inst.discounted[51], commission: inst.discounted[2] }; var installment_without_tax = { date: inst.date, monthlyPaymentDate: inst.monthlyPaymentDate, payment: inst.payment, original: { principal: inst.original[1] / (1 + (this.pricelists[1] && this.pricelists[1].tax_percentage ? parseFloat(this.pricelists[1].tax_percentage) : 0 )), interest: inst.original[51] / (1 + parseFloat(0.000)), commission: inst.original[2] / (1 + (this.pricelists[2] && this.pricelists[2].tax_percentage ? parseFloat(this.pricelists[2].tax_percentage): 0 )) }, principal: inst.discounted[1] / (1 + (this.pricelists[1] && this.pricelists[1].tax_percentage ? parseFloat(this.pricelists[1].tax_percentage) : 0 )), interest: inst.discounted[51] / (1 + parseFloat(0.000)), commission: inst.discounted[2] / (1 + (this.pricelists[2] && this.pricelists[2].tax_percentage ? parseFloat(this.pricelists[2].tax_percentage) : 0)) }; installment_without_tax.payment = installment_without_tax.principal + installment_without_tax.interest + installment_without_tax.commission; _all_installments.push(installment); _all_installments_without_tax.push(installment_without_tax); for (var id in inst.original) { if (!isNaN(id)) { if (!(id in values.discounted)) { values.discounted[id] = 0; } values.discounted[id] += inst.discounted[id]; if (!(id in values.prices)) { values.prices[id] = 0; } values.prices[id] += inst.original[id]; if (!(id in values.discounts)) { values.discounts[id] = 0; } values.discounts[id] += inst.discounts[id]; } } } var loan_total = values.discounted[1] + values.discounted[2] + values.discounted[51]; var loan_total_without_tax = (values.discounted_without_tax[1] || values.discounted[1]) + (values.discounted_without_tax[2] || values.discounted[2]); for (var id in values.prices) { var discountPercentAr = values.discounts_per[id]; var name = ''; if (id in this.pricelists) { name = this.pricelists[id].type; } else if (id == 51) { name = 'interest-fee'; } else if (id == 2) { name = 'loan-fee'; } if (discountPercentAr) { details2['percent-discounts'][name] = discountPercentAr; } var discountAmountAr = values.discounts_amn[id]; if (discountAmountAr) { details2['amount-discounts'][name] = discountAmountAr; } if (values.prices_without_tax[id]) { values.discounted_without_tax[id] = parseFloat((values.discounted[id] / (1 + parseFloat(this.pricelists[id].tax_percentage))).toFixed(2)); values.discounts_without_tax[id] = parseFloat((values.prices_without_tax[id] - values.discounted_without_tax[id]).toFixed(2)); } } var creditLimitResult = null; for (var id in values.prices) { var name = ''; if (id in this.pricelists) { name = this.pricelists[id].type; } else if (id == 51) { name = 'interest-fee'; } else if (id == 2) { name = 'loan-fee'; } details2.original[name] = values.prices[id]; details2.discount[name] = values.discounts[id]; details2.final[name] = values.discounted[id]; details2.without_tax.original[name] = values.prices_without_tax[id] || values.prices[id]; details2.without_tax.discount[name] = values.discounts_without_tax[id] || values.discounts[id]; details2.without_tax.final[name] = values.discounted_without_tax[id] || values.discounted[id]; if (id in this.pricelists) { details2.tax_percentage[name] = parseFloat(this.pricelists[id].tax_percentage || 0); details2.without_tax.original[name] = values.prices_without_tax[id] || values.prices[id]; details2.without_tax.discount[name] = values.discounts_without_tax[id] || values.discounts[id]; details2.without_tax.final[name] = values.discounted_without_tax[id] || values.discounted[id]; } else { var interest_tax_percantage = parseFloat(0.000); details2.tax_percentage[name] = parseFloat(interest_tax_percantage || 0); details2.without_tax.original[name] = parseFloat(values.prices[id] / (1 + interest_tax_percantage)).toFixed(2); details2.without_tax.discount[name] = parseFloat(values.discounts[id] / (1 + interest_tax_percantage)).toFixed(2); details2.without_tax.final[name] = parseFloat(values.discounted[id] / (1 + interest_tax_percantage)).toFixed(2); } } if ((bag[-15] || false) == false) { delete details2.without_tax; delete details2.tax_percentage; } var ret = { 'loan-amount': bag[-3], 'loan-term': bag[-2], 'loan-repay-amount': values.discounted[1], 'loan-fees': values.discounted[2], 'loan-original-fees': values.prices[2], 'loan-total': loan_total, 'loan-free-extension': values.total_extension_term, 'loan-interest-fees': values.discounted['51'], 'loan-original-interest-fees': values.prices['51'], 'creditline-percent-principal-repay-month': 0.1500000000, 'creditline-percent-principal-month': 0.0400000000, 'creditline-percent-creditline-month': 0.0000000000, 'creditline-percent-creditline-fallback-month': 0.0000000000, 'creditline-min-monthly-payment': 0.00, 'creditline-annual-interest-rate': (values.feeRates[51]/ 100).toFixed(10), 'creditline-monthly-interest-rate': (values.feeRates[51]/ 100 / 12).toFixed(10), details: details2, installments: _all_installments, installments_without_tax: _all_installments_without_tax, 'loan-duedate': _all_installments[_all_installments.length - 1].date }; if (apr == true) { var daysInYear = 365; var forcePayoutDate = bag["calculation-date"] ? bag["calculation-date"] : bag[-16] ? bag[-16] : null; ret['loan-apr'] = this.XIRR(parseFloat(bag[-3]), ((bag[-15] || false) == false) ? _all_installments : _all_installments_without_tax, null, forcePayoutDate, daysInYear); } if (values.customer_data) { ret['customer-data'] = values.customer_data; } if (values.feeRates) { ret['fee-rates'] = values.feeRates; } if (creditLimitResult) { ret['loan-credit-limit'] = creditLimitResult.limit; } return ret; }, additional_data: { distribute_equal: true, }, fields: { 460: 'Status', 799: 'Loan count', 802: 'Delay', 1217: 'Id', 2438: 'Is First Loan', 2538: 'Verification Mode', 2788: 'Open principal', 3141: 'Product', 3251: 'Has Open Payday Loan', 3252: 'Has Open Creditline', 3253: 'Has Open Installment Loan', 3256: 'Next installment remaining debt', 3353: 'Installment Delay', 4102: 'Late installment remaining debt (w/o LF)', 5266: 'is active early settlement', 5320: 'Repaid installments count', 6054: 'Last Instantor Succesful Verification', 7560: 'is_force_settled', }, dateValidationDefinition: { evaluate: function (bag) { var control = { canceled: false, quit: false }; (function () { bag["isValid"](); })(); return control; }, freshBag: function (bag, date_to_check) { var n = { date_to_check: date_to_check, holidays: [], valid: false, confirmDate: function (checkDate) { var resultDate = null; if (checkDate === null) { checkDate = "1900-01-01"; } // Check if it is a correct Date object if (checkDate instanceof Date && !isNaN(checkDate.getMonth())) { resultDate = checkDate; } if (typeof checkDate === 'string') { resultDate = new Date(checkDate); // Check if it is a correct date if (isNaN(resultDate.getMonth())) { resultDate = new Date("1900-01-01"); } } if (resultDate === null) { resultDate = new Date("1900-01-01"); } resultDate = new Date(this.getDateToString(resultDate)); resultDate.setMinutes(resultDate.getMinutes() + resultDate.getTimezoneOffset()); return resultDate; }, getDateToString: function (date) { return date.getFullYear() + '-' + ("0" + (date.getMonth() + 1 )).slice(-2) + '-' + ("0" + date.getDate()).slice(-2); }, getValidDateToString: function () { if (!this.valid) { return null; } var date = this.confirmDate(this.date_to_check); return this.getDateToString(date); }, getDay: function () { var date = this.confirmDate(this.date_to_check); return date.getDate(); }, getMonth: function () { var date = this.confirmDate(this.date_to_check); // date.getMonth is 0-indexed return (date.getMonth() + 1); }, getYear: function () { var date = this.confirmDate(this.date_to_check); return date.getFullYear(); }, getDayOfWeek: function () { var date = this.confirmDate(this.date_to_check); return date.getDay(); }, daysInCurrentMonth: function () { var date = this.confirmDate(new Date()); return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(); }, isHoliday: function () { var date = this.confirmDate(this.date_to_check); for(var i = 0; i < this.holidays.length; ++i) { holiday = this.confirmDate(this.holidays[i]); if (Date.parse(date) === Date.parse(holiday)) { return true; } } return false; }, daysFromNow: function () { var now = this.confirmDate(new Date()); var dateToCheck = this.confirmDate(this.date_to_check); var diff = Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()) - Date.UTC(dateToCheck.getFullYear(), dateToCheck.getMonth(), dateToCheck.getDate()); return (Math.floor(diff / (24 * 60 * 60 * 1000)) * -1); }, isValid: function () { this.valid = true; } }; for (var id in bag) { if (!(id in n)) { n[id] = bag[id]; } } return n; }, getRange: function (wished_range) { var max_range = 50; if (wished_range === null || wished_range > max_range || wished_range < 1) { return max_range; } return wished_range; }, getOffset: function (wished_offset) { var min_offset = 0; if (wished_offset === null || wished_offset < min_offset) { return min_offset; } return wished_offset; }, getValidDates: function (bag, offset, range) { range = this.getRange(range); var date = new Date(); date.setDate(date.getDate() + parseInt(this.getOffset(offset))); var validDays = []; for (var i = 0; i < range; i++) { var _date = new Date(date); _date.setDate(_date.getDate() + i); var ibag = this.freshBag(bag, _date); this.evaluate(ibag); if (ibag.valid) { validDays.push(ibag.getValidDateToString()); } } return validDays; }, }, calculateCreditLimitPayoutFees: function(bag) { return this.evaluate(bag); }, }, payday: { pricelists: { '1': { type: 'principal', fee_type_id: '1', tax_percentage: '0.000', data: {}, dimension: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if (true) { (bag['setAmountRange'](50, 215, 5) * bag['setTermRange'](7, 30, 1)); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, price: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if (true) { vars['amn'] = bag['getAmount'](); bag['setPrice'](vars['amn']); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, buildDimension: function (bag = {}) { if (!this.amounts) { var amounts = []; var terms = []; bag = Object.assign({ setAmountRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (amounts.indexOf(i) === -1) { amounts.push(i); } } }, setTermRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (terms.indexOf(i) === -1) { terms.push(i); } } } }, bag); this.dimension.evaluate(bag); amounts.sort(function (a, b) { return a - b; }); terms.sort(function (a, b) { return a - b; }); this.amounts = amounts; this.terms = terms; } return { amounts: this.amounts, terms: this.terms }; }, buildPrice: function (amount, term, pricelist_bag) { var price = null; var rate = 0; var pricebag = pricelist_bag || {}; pricebag.getAmount = function () { return parseFloat(amount); }; pricebag.getTerm = function () { return parseFloat(term); }; pricebag.setPrice = function (data) { price = data; }; pricebag.setRate = function (data) { rate = data; }; pricebag.parseFloat = parseFloat; this.price.evaluate(pricebag); return { price: parseFloat(price).toFixed(2), rate: parseFloat(rate).toFixed(10) }; } }, '2': { type: 'loan-fee', fee_type_id: '2', tax_percentage: '0.000', data: {}, dimension: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if (true) { (bag['setAmountRange'](50, 215, 5) * bag['setTermRange'](7, 30, 1)); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, price: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if (true) { vars['am'] = bag['getAmount'](); if (control.canceled) return; vars['loanterm'] = bag['getTerm'](); if (control.canceled) return; vars['final'] = ((vars['am'] * 0.0029333333) * vars['loanterm']); if (control.canceled) return; bag['setPrice'](vars['final']); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, buildDimension: function (bag = {}) { if (!this.amounts) { var amounts = []; var terms = []; bag = Object.assign({ setAmountRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (amounts.indexOf(i) === -1) { amounts.push(i); } } }, setTermRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (terms.indexOf(i) === -1) { terms.push(i); } } } }, bag); this.dimension.evaluate(bag); amounts.sort(function (a, b) { return a - b; }); terms.sort(function (a, b) { return a - b; }); this.amounts = amounts; this.terms = terms; } return { amounts: this.amounts, terms: this.terms }; }, buildPrice: function (amount, term, pricelist_bag) { var price = null; var rate = 0; var pricebag = pricelist_bag || {}; pricebag.getAmount = function () { return parseFloat(amount); }; pricebag.getTerm = function () { return parseFloat(term); }; pricebag.setPrice = function (data) { price = data; }; pricebag.setRate = function (data) { rate = data; }; pricebag.parseFloat = parseFloat; this.price.evaluate(pricebag); return { price: parseFloat(price).toFixed(2), rate: parseFloat(rate).toFixed(10) }; } }, '4': { type: 'extension-fee', fee_type_id: '4', tax_percentage: '0.000', data: {}, dimension: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Set dimensions (function () { // Group: Group if (true) { bag['setAmountRange'](5, 700, 5); if (control.canceled) return; bag['setTermRange'](30, 30, 30); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, price: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Variables (function () { // Group: Group if (bag[799] == 0) { vars['finalprice'] = (bag[-3] * 0.075); vars['tterm'] = bag['getTerm'](); if (control.canceled) return; } else { vars['sumdisc'] = (bag[2789] - bag[4054]); if (control.canceled) return; vars['maxprice'] = (bag[-3] * 0.075); if (control.canceled) return; vars['temprice'] = ((bag[-3] * 0.06) + vars['sumdisc']); if (control.canceled) return; vars['check'] = (vars['maxprice'] - vars['temprice']); if (control.canceled) return; vars['tterm'] = bag['getTerm'](); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: First ext check if ((vars['check'] <= 0 && (bag[3626] == 0 && bag[799] != 0))) { vars['finalprice'] = vars['maxprice']; if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: First ext check if ((vars['check'] > 0 && (bag[3626] == 0 && bag[799] != 0))) { vars['finalprice'] = vars['temprice']; if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Next ext check if ((bag[3626] != 0 && bag[799] != 0)) { vars['finalprice'] = (bag[-3] * 0.06); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: Term check (function () { // Group: Group if (vars['tterm'] == 30) { bag['setPrice'](vars['finalprice']); if (control.canceled) return; } else { vars['finalprice'] = (vars['finalprice'] / 2); bag['setPrice'](vars['finalprice']); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, buildDimension: function (bag = {}) { if (!this.amounts) { var amounts = []; var terms = []; bag = Object.assign({ setAmountRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (amounts.indexOf(i) === -1) { amounts.push(i); } } }, setTermRange: function (min, max, step) { if (!Number.isInteger(min) || !Number.isInteger(max) || !Number.isInteger(step) || step <= 0 || min > max) { throw new Error('Parameters provided are not defined or have a wrong value'); } for (var i = min; i <= max; i += step) { if (terms.indexOf(i) === -1) { terms.push(i); } } } }, bag); this.dimension.evaluate(bag); amounts.sort(function (a, b) { return a - b; }); terms.sort(function (a, b) { return a - b; }); this.amounts = amounts; this.terms = terms; } return { amounts: this.amounts, terms: this.terms }; }, buildPrice: function (amount, term, pricelist_bag) { var price = null; var rate = 0; var pricebag = pricelist_bag || {}; pricebag.getAmount = function () { return parseFloat(amount); }; pricebag.getTerm = function () { return parseFloat(term); }; pricebag.setPrice = function (data) { price = data; }; pricebag.setRate = function (data) { rate = data; }; pricebag.parseFloat = parseFloat; this.price.evaluate(pricebag); return { price: parseFloat(price).toFixed(2), rate: parseFloat(rate).toFixed(10) }; } }, }, additional_payout_pricelist: { type: 'additional-payout-fee', fee_type_id: '2', tax_percentage: '0.000', amounts: ["5.00","10.00","15.00","20.00","25.00","30.00","35.00","40.00","45.00","50.00","55.00","60.00","65.00","70.00","75.00","80.00","85.00","90.00","95.00","100.00","105.00","110.00","115.00","120.00","125.00","130.00","135.00","140.00","145.00","150.00","155.00","160.00","165.00","170.00","175.00","180.00","185.00","190.00","195.00","200.00","205.00","210.00","215.00","220.00","225.00","230.00","235.00","240.00","245.00","250.00","255.00","260.00","265.00","270.00","275.00","280.00","285.00","290.00","295.00","300.00","305.00","310.00","315.00","320.00","325.00","330.00","335.00","340.00","345.00","350.00","355.00","360.00","365.00","370.00","375.00","380.00","385.00","390.00","395.00","400.00","405.00","410.00","415.00","420.00","425.00","430.00","435.00","440.00","445.00","450.00","455.00","460.00","465.00","470.00","475.00","480.00","485.00","490.00","495.00","500.00","505.00","510.00","515.00","520.00","525.00","530.00","535.00","540.00","545.00","550.00","555.00","560.00","565.00","570.00","575.00","580.00","585.00","590.00","595.00","600.00","605.00","610.00","615.00","620.00","625.00","630.00","635.00","640.00","645.00","650.00","655.00","660.00","665.00","670.00","675.00","680.00","685.00","690.00","695.00","700.00"], terms: ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30"], data: {"5.00":{"1":"0.03","2":"0.06","3":"0.08","4":"0.11","5":"0.14","6":"0.17","7":"0.19","8":"0.21","9":"0.22","10":"0.23","11":"0.24","12":"0.26","13":"0.27","14":"0.28","15":"0.29","16":"0.30","17":"0.31","18":"0.32","19":"0.33","20":"0.34","21":"0.35","22":"0.36","23":"0.37","24":"0.38","25":"0.39","26":"0.40","27":"0.41","28":"0.42","29":"0.43","30":"0.44"},"10.00":{"1":"0.06","2":"0.11","3":"0.17","4":"0.22","5":"0.28","6":"0.33","7":"0.39","8":"0.41","9":"0.43","10":"0.46","11":"0.48","12":"0.51","13":"0.53","14":"0.56","15":"0.58","16":"0.60","17":"0.62","18":"0.64","19":"0.66","20":"0.68","21":"0.70","22":"0.72","23":"0.74","24":"0.76","25":"0.78","26":"0.80","27":"0.82","28":"0.84","29":"0.86","30":"0.88"},"15.00":{"1":"0.08","2":"0.17","3":"0.25","4":"0.33","5":"0.41","6":"0.50","7":"0.58","8":"0.62","9":"0.65","10":"0.69","11":"0.73","12":"0.77","13":"0.80","14":"0.84","15":"0.87","16":"0.90","17":"0.93","18":"0.96","19":"0.99","20":"1.02","21":"1.05","22":"1.08","23":"1.11","24":"1.14","25":"1.17","26":"1.20","27":"1.23","28":"1.26","29":"1.29","30":"1.32"},"20.00":{"1":"0.11","2":"0.22","3":"0.33","4":"0.44","5":"0.55","6":"0.66","7":"0.77","8":"0.82","9":"0.87","10":"0.92","11":"0.97","12":"1.02","13":"1.07","14":"1.12","15":"1.16","16":"1.20","17":"1.24","18":"1.28","19":"1.32","20":"1.36","21":"1.40","22":"1.44","23":"1.48","24":"1.52","25":"1.56","26":"1.60","27":"1.64","28":"1.68","29":"1.72","30":"1.76"},"25.00":{"1":"0.14","2":"0.28","3":"0.41","4":"0.55","5":"0.69","6":"0.83","7":"0.96","8":"1.03","9":"1.09","10":"1.15","11":"1.21","12":"1.28","13":"1.34","14":"1.40","15":"1.45","16":"1.50","17":"1.55","18":"1.60","19":"1.65","20":"1.70","21":"1.75","22":"1.80","23":"1.85","24":"1.90","25":"1.95","26":"2.00","27":"2.05","28":"2.10","29":"2.15","30":"2.20"},"30.00":{"1":"0.17","2":"0.33","3":"0.50","4":"0.66","5":"0.83","6":"0.99","7":"1.16","8":"1.23","9":"1.30","10":"1.38","11":"1.45","12":"1.53","13":"1.60","14":"1.68","15":"1.74","16":"1.80","17":"1.86","18":"1.92","19":"1.98","20":"2.04","21":"2.10","22":"2.16","23":"2.22","24":"2.28","25":"2.34","26":"2.40","27":"2.46","28":"2.52","29":"2.58","30":"2.64"},"35.00":{"1":"0.19","2":"0.39","3":"0.58","4":"0.77","5":"0.96","6":"1.16","7":"1.35","8":"1.44","9":"1.52","10":"1.61","11":"1.70","12":"1.79","13":"1.87","14":"1.96","15":"2.03","16":"2.10","17":"2.17","18":"2.24","19":"2.31","20":"2.38","21":"2.45","22":"2.52","23":"2.59","24":"2.66","25":"2.73","26":"2.80","27":"2.87","28":"2.94","29":"3.01","30":"3.08"},"40.00":{"1":"0.22","2":"0.44","3":"0.66","4":"0.88","5":"1.10","6":"1.32","7":"1.54","8":"1.64","9":"1.74","10":"1.84","11":"1.94","12":"2.04","13":"2.14","14":"2.24","15":"2.32","16":"2.40","17":"2.48","18":"2.56","19":"2.64","20":"2.72","21":"2.80","22":"2.88","23":"2.96","24":"3.04","25":"3.12","26":"3.20","27":"3.28","28":"3.36","29":"3.44","30":"3.52"},"45.00":{"1":"0.25","2":"0.50","3":"0.74","4":"0.99","5":"1.24","6":"1.49","7":"1.73","8":"1.85","9":"1.96","10":"2.07","11":"2.18","12":"2.30","13":"2.41","14":"2.52","15":"2.61","16":"2.70","17":"2.79","18":"2.88","19":"2.97","20":"3.06","21":"3.15","22":"3.24","23":"3.33","24":"3.42","25":"3.51","26":"3.60","27":"3.69","28":"3.78","29":"3.87","30":"3.96"},"50.00":{"1":"0.28","2":"0.55","3":"0.83","4":"1.10","5":"1.38","6":"1.65","7":"1.93","8":"2.05","9":"2.17","10":"2.30","11":"2.42","12":"2.55","13":"2.67","14":"2.80","15":"2.90","16":"3.00","17":"3.10","18":"3.20","19":"3.30","20":"3.40","21":"3.50","22":"3.60","23":"3.70","24":"3.80","25":"3.90","26":"4.00","27":"4.10","28":"4.20","29":"4.30","30":"4.40"},"55.00":{"1":"0.30","2":"0.61","3":"0.91","4":"1.21","5":"1.51","6":"1.82","7":"2.12","8":"2.26","9":"2.39","10":"2.53","11":"2.67","12":"2.81","13":"2.94","14":"3.08","15":"3.19","16":"3.30","17":"3.41","18":"3.52","19":"3.63","20":"3.74","21":"3.85","22":"3.96","23":"4.07","24":"4.18","25":"4.29","26":"4.40","27":"4.51","28":"4.62","29":"4.73","30":"4.84"},"60.00":{"1":"0.33","2":"0.66","3":"0.99","4":"1.32","5":"1.65","6":"1.98","7":"2.31","8":"2.46","9":"2.61","10":"2.76","11":"2.91","12":"3.06","13":"3.21","14":"3.36","15":"3.48","16":"3.60","17":"3.72","18":"3.84","19":"3.96","20":"4.08","21":"4.20","22":"4.32","23":"4.44","24":"4.56","25":"4.68","26":"4.80","27":"4.92","28":"5.04","29":"5.16","30":"5.28"},"65.00":{"1":"0.36","2":"0.72","3":"1.07","4":"1.43","5":"1.79","6":"2.15","7":"2.50","8":"2.67","9":"2.83","10":"2.99","11":"3.15","12":"3.32","13":"3.48","14":"3.64","15":"3.77","16":"3.90","17":"4.03","18":"4.16","19":"4.29","20":"4.42","21":"4.55","22":"4.68","23":"4.81","24":"4.94","25":"5.07","26":"5.20","27":"5.33","28":"5.46","29":"5.59","30":"5.72"},"70.00":{"1":"0.39","2":"0.77","3":"1.16","4":"1.54","5":"1.93","6":"2.31","7":"2.70","8":"2.87","9":"3.04","10":"3.22","11":"3.39","12":"3.57","13":"3.74","14":"3.92","15":"4.06","16":"4.20","17":"4.34","18":"4.48","19":"4.62","20":"4.76","21":"4.90","22":"5.04","23":"5.18","24":"5.32","25":"5.46","26":"5.60","27":"5.74","28":"5.88","29":"6.02","30":"6.16"},"75.00":{"1":"0.41","2":"0.83","3":"1.24","4":"1.65","5":"2.06","6":"2.48","7":"2.89","8":"3.08","9":"3.26","10":"3.45","11":"3.64","12":"3.83","13":"4.01","14":"4.20","15":"4.35","16":"4.50","17":"4.65","18":"4.80","19":"4.95","20":"5.10","21":"5.25","22":"5.40","23":"5.55","24":"5.70","25":"5.85","26":"6.00","27":"6.15","28":"6.30","29":"6.45","30":"6.60"},"80.00":{"1":"0.44","2":"0.88","3":"1.32","4":"1.76","5":"2.20","6":"2.64","7":"3.08","8":"3.28","9":"3.48","10":"3.68","11":"3.88","12":"4.08","13":"4.28","14":"4.48","15":"4.64","16":"4.80","17":"4.96","18":"5.12","19":"5.28","20":"5.44","21":"5.60","22":"5.76","23":"5.92","24":"6.08","25":"6.24","26":"6.40","27":"6.56","28":"6.72","29":"6.88","30":"7.04"},"85.00":{"1":"0.47","2":"0.94","3":"1.40","4":"1.87","5":"2.34","6":"2.81","7":"3.27","8":"3.49","9":"3.70","10":"3.91","11":"4.12","12":"4.34","13":"4.55","14":"4.76","15":"4.93","16":"5.10","17":"5.27","18":"5.44","19":"5.61","20":"5.78","21":"5.95","22":"6.12","23":"6.29","24":"6.46","25":"6.63","26":"6.80","27":"6.97","28":"7.14","29":"7.31","30":"7.48"},"90.00":{"1":"0.50","2":"0.99","3":"1.49","4":"1.98","5":"2.48","6":"2.97","7":"3.47","8":"3.69","9":"3.91","10":"4.14","11":"4.36","12":"4.59","13":"4.81","14":"5.04","15":"5.22","16":"5.40","17":"5.58","18":"5.76","19":"5.94","20":"6.12","21":"6.30","22":"6.48","23":"6.66","24":"6.84","25":"7.02","26":"7.20","27":"7.38","28":"7.56","29":"7.74","30":"7.92"},"95.00":{"1":"0.52","2":"1.05","3":"1.57","4":"2.09","5":"2.61","6":"3.14","7":"3.66","8":"3.90","9":"4.13","10":"4.37","11":"4.61","12":"4.85","13":"5.08","14":"5.32","15":"5.51","16":"5.70","17":"5.89","18":"6.08","19":"6.27","20":"6.46","21":"6.65","22":"6.84","23":"7.03","24":"7.22","25":"7.41","26":"7.60","27":"7.79","28":"7.98","29":"8.17","30":"8.36"},"100.00":{"1":"0.55","2":"1.10","3":"1.65","4":"2.20","5":"2.75","6":"3.30","7":"3.85","8":"4.10","9":"4.35","10":"4.60","11":"4.85","12":"5.10","13":"5.35","14":"5.60","15":"5.80","16":"6.00","17":"6.20","18":"6.40","19":"6.60","20":"6.80","21":"7.00","22":"7.20","23":"7.40","24":"7.60","25":"7.80","26":"8.00","27":"8.20","28":"8.40","29":"8.60","30":"8.80"},"105.00":{"1":"0.58","2":"1.16","3":"1.73","4":"2.31","5":"2.89","6":"3.47","7":"4.04","8":"4.31","9":"4.57","10":"4.83","11":"5.09","12":"5.36","13":"5.62","14":"5.88","15":"6.09","16":"6.30","17":"6.51","18":"6.72","19":"6.93","20":"7.14","21":"7.35","22":"7.56","23":"7.77","24":"7.98","25":"8.19","26":"8.40","27":"8.61","28":"8.82","29":"9.03","30":"9.24"},"110.00":{"1":"0.61","2":"1.21","3":"1.82","4":"2.42","5":"3.03","6":"3.63","7":"4.24","8":"4.51","9":"4.78","10":"5.06","11":"5.33","12":"5.61","13":"5.88","14":"6.16","15":"6.38","16":"6.60","17":"6.82","18":"7.04","19":"7.26","20":"7.48","21":"7.70","22":"7.92","23":"8.14","24":"8.36","25":"8.58","26":"8.80","27":"9.02","28":"9.24","29":"9.46","30":"9.68"},"115.00":{"1":"0.63","2":"1.27","3":"1.90","4":"2.53","5":"3.16","6":"3.80","7":"4.43","8":"4.72","9":"5.00","10":"5.29","11":"5.58","12":"5.87","13":"6.15","14":"6.44","15":"6.67","16":"6.90","17":"7.13","18":"7.36","19":"7.59","20":"7.82","21":"8.05","22":"8.28","23":"8.51","24":"8.74","25":"8.97","26":"9.20","27":"9.43","28":"9.66","29":"9.89","30":"10.12"},"120.00":{"1":"0.66","2":"1.32","3":"1.98","4":"2.64","5":"3.30","6":"3.96","7":"4.62","8":"4.92","9":"5.22","10":"5.52","11":"5.82","12":"6.12","13":"6.42","14":"6.72","15":"6.96","16":"7.20","17":"7.44","18":"7.68","19":"7.92","20":"8.16","21":"8.40","22":"8.64","23":"8.88","24":"9.12","25":"9.36","26":"9.60","27":"9.84","28":"10.08","29":"10.32","30":"10.56"},"125.00":{"1":"0.69","2":"1.38","3":"2.06","4":"2.75","5":"3.44","6":"4.13","7":"4.81","8":"5.13","9":"5.44","10":"5.75","11":"6.06","12":"6.38","13":"6.69","14":"7.00","15":"7.25","16":"7.50","17":"7.75","18":"8.00","19":"8.25","20":"8.50","21":"8.75","22":"9.00","23":"9.25","24":"9.50","25":"9.75","26":"10.00","27":"10.25","28":"10.50","29":"10.75","30":"11.00"},"130.00":{"1":"0.72","2":"1.43","3":"2.15","4":"2.86","5":"3.58","6":"4.29","7":"5.01","8":"5.33","9":"5.65","10":"5.98","11":"6.30","12":"6.63","13":"6.95","14":"7.28","15":"7.54","16":"7.80","17":"8.06","18":"8.32","19":"8.58","20":"8.84","21":"9.10","22":"9.36","23":"9.62","24":"9.88","25":"10.14","26":"10.40","27":"10.66","28":"10.92","29":"11.18","30":"11.44"},"135.00":{"1":"0.74","2":"1.49","3":"2.23","4":"2.97","5":"3.71","6":"4.46","7":"5.20","8":"5.54","9":"5.87","10":"6.21","11":"6.55","12":"6.89","13":"7.22","14":"7.56","15":"7.83","16":"8.10","17":"8.37","18":"8.64","19":"8.91","20":"9.18","21":"9.45","22":"9.72","23":"9.99","24":"10.26","25":"10.53","26":"10.80","27":"11.07","28":"11.34","29":"11.61","30":"11.88"},"140.00":{"1":"0.77","2":"1.54","3":"2.31","4":"3.08","5":"3.85","6":"4.62","7":"5.39","8":"5.74","9":"6.09","10":"6.44","11":"6.79","12":"7.14","13":"7.49","14":"7.84","15":"8.12","16":"8.40","17":"8.68","18":"8.96","19":"9.24","20":"9.52","21":"9.80","22":"10.08","23":"10.36","24":"10.64","25":"10.92","26":"11.20","27":"11.48","28":"11.76","29":"12.04","30":"12.32"},"145.00":{"1":"0.80","2":"1.60","3":"2.39","4":"3.19","5":"3.99","6":"4.79","7":"5.58","8":"5.95","9":"6.31","10":"6.67","11":"7.03","12":"7.40","13":"7.76","14":"8.12","15":"8.41","16":"8.70","17":"8.99","18":"9.28","19":"9.57","20":"9.86","21":"10.15","22":"10.44","23":"10.73","24":"11.02","25":"11.31","26":"11.60","27":"11.89","28":"12.18","29":"12.47","30":"12.76"},"150.00":{"1":"0.83","2":"1.65","3":"2.48","4":"3.30","5":"4.13","6":"4.95","7":"5.78","8":"6.15","9":"6.52","10":"6.90","11":"7.27","12":"7.65","13":"8.02","14":"8.40","15":"8.70","16":"9.00","17":"9.30","18":"9.60","19":"9.90","20":"10.20","21":"10.50","22":"10.80","23":"11.10","24":"11.40","25":"11.70","26":"12.00","27":"12.30","28":"12.60","29":"12.90","30":"13.20"},"155.00":{"1":"0.85","2":"1.71","3":"2.56","4":"3.41","5":"4.26","6":"5.12","7":"5.97","8":"6.36","9":"6.74","10":"7.13","11":"7.52","12":"7.91","13":"8.29","14":"8.68","15":"8.99","16":"9.30","17":"9.61","18":"9.92","19":"10.23","20":"10.54","21":"10.85","22":"11.16","23":"11.47","24":"11.78","25":"12.09","26":"12.40","27":"12.71","28":"13.02","29":"13.33","30":"13.64"},"160.00":{"1":"0.88","2":"1.76","3":"2.64","4":"3.52","5":"4.40","6":"5.28","7":"6.16","8":"6.56","9":"6.96","10":"7.36","11":"7.76","12":"8.16","13":"8.56","14":"8.96","15":"9.28","16":"9.60","17":"9.92","18":"10.24","19":"10.56","20":"10.88","21":"11.20","22":"11.52","23":"11.84","24":"12.16","25":"12.48","26":"12.80","27":"13.12","28":"13.44","29":"13.76","30":"14.08"},"165.00":{"1":"0.91","2":"1.82","3":"2.72","4":"3.63","5":"4.54","6":"5.45","7":"6.35","8":"6.77","9":"7.18","10":"7.59","11":"8.00","12":"8.42","13":"8.83","14":"9.24","15":"9.57","16":"9.90","17":"10.23","18":"10.56","19":"10.89","20":"11.22","21":"11.55","22":"11.88","23":"12.21","24":"12.54","25":"12.87","26":"13.20","27":"13.53","28":"13.86","29":"14.19","30":"14.52"},"170.00":{"1":"0.94","2":"1.87","3":"2.81","4":"3.74","5":"4.68","6":"5.61","7":"6.55","8":"6.97","9":"7.39","10":"7.82","11":"8.24","12":"8.67","13":"9.09","14":"9.52","15":"9.86","16":"10.20","17":"10.54","18":"10.88","19":"11.22","20":"11.56","21":"11.90","22":"12.24","23":"12.58","24":"12.92","25":"13.26","26":"13.60","27":"13.94","28":"14.28","29":"14.62","30":"14.96"},"175.00":{"1":"0.96","2":"1.93","3":"2.89","4":"3.85","5":"4.81","6":"5.78","7":"6.74","8":"7.18","9":"7.61","10":"8.05","11":"8.49","12":"8.93","13":"9.36","14":"9.80","15":"10.15","16":"10.50","17":"10.85","18":"11.20","19":"11.55","20":"11.90","21":"12.25","22":"12.60","23":"12.95","24":"13.30","25":"13.65","26":"14.00","27":"14.35","28":"14.70","29":"15.05","30":"15.40"},"180.00":{"1":"0.99","2":"1.98","3":"2.97","4":"3.96","5":"4.95","6":"5.94","7":"6.93","8":"7.38","9":"7.83","10":"8.28","11":"8.73","12":"9.18","13":"9.63","14":"10.08","15":"10.44","16":"10.80","17":"11.16","18":"11.52","19":"11.88","20":"12.24","21":"12.60","22":"12.96","23":"13.32","24":"13.68","25":"14.04","26":"14.40","27":"14.76","28":"15.12","29":"15.48","30":"15.84"},"185.00":{"1":"1.02","2":"2.04","3":"3.05","4":"4.07","5":"5.09","6":"6.11","7":"7.12","8":"7.59","9":"8.05","10":"8.51","11":"8.97","12":"9.44","13":"9.90","14":"10.36","15":"10.73","16":"11.10","17":"11.47","18":"11.84","19":"12.21","20":"12.58","21":"12.95","22":"13.32","23":"13.69","24":"14.06","25":"14.43","26":"14.80","27":"15.17","28":"15.54","29":"15.91","30":"16.28"},"190.00":{"1":"1.05","2":"2.09","3":"3.14","4":"4.18","5":"5.23","6":"6.27","7":"7.32","8":"7.79","9":"8.26","10":"8.74","11":"9.21","12":"9.69","13":"10.16","14":"10.64","15":"11.02","16":"11.40","17":"11.78","18":"12.16","19":"12.54","20":"12.92","21":"13.30","22":"13.68","23":"14.06","24":"14.44","25":"14.82","26":"15.20","27":"15.58","28":"15.96","29":"16.34","30":"16.72"},"195.00":{"1":"1.07","2":"2.15","3":"3.22","4":"4.29","5":"5.36","6":"6.44","7":"7.51","8":"8.00","9":"8.48","10":"8.97","11":"9.46","12":"9.95","13":"10.43","14":"10.92","15":"11.31","16":"11.70","17":"12.09","18":"12.48","19":"12.87","20":"13.26","21":"13.65","22":"14.04","23":"14.43","24":"14.82","25":"15.21","26":"15.60","27":"15.99","28":"16.38","29":"16.77","30":"17.16"},"200.00":{"1":"1.10","2":"2.20","3":"3.30","4":"4.40","5":"5.50","6":"6.60","7":"7.70","8":"8.20","9":"8.70","10":"9.20","11":"9.70","12":"10.20","13":"10.70","14":"11.20","15":"11.60","16":"12.00","17":"12.40","18":"12.80","19":"13.20","20":"13.60","21":"14.00","22":"14.40","23":"14.80","24":"15.20","25":"15.60","26":"16.00","27":"16.40","28":"16.80","29":"17.20","30":"17.60"},"205.00":{"1":"1.13","2":"2.26","3":"3.38","4":"4.51","5":"5.64","6":"6.77","7":"7.89","8":"8.41","9":"8.92","10":"9.43","11":"9.94","12":"10.46","13":"10.97","14":"11.48","15":"11.89","16":"12.30","17":"12.71","18":"13.12","19":"13.53","20":"13.94","21":"14.35","22":"14.76","23":"15.17","24":"15.58","25":"15.99","26":"16.40","27":"16.81","28":"17.22","29":"17.63","30":"18.04"},"210.00":{"1":"1.16","2":"2.31","3":"3.47","4":"4.62","5":"5.78","6":"6.93","7":"8.09","8":"8.61","9":"9.13","10":"9.66","11":"10.18","12":"10.71","13":"11.23","14":"11.76","15":"12.18","16":"12.60","17":"13.02","18":"13.44","19":"13.86","20":"14.28","21":"14.70","22":"15.12","23":"15.54","24":"15.96","25":"16.38","26":"16.80","27":"17.22","28":"17.64","29":"18.06","30":"18.48"},"215.00":{"1":"1.18","2":"2.37","3":"3.55","4":"4.73","5":"5.91","6":"7.10","7":"8.28","8":"8.82","9":"9.35","10":"9.89","11":"10.43","12":"10.97","13":"11.50","14":"12.04","15":"12.47","16":"12.90","17":"13.33","18":"13.76","19":"14.19","20":"14.62","21":"15.05","22":"15.48","23":"15.91","24":"16.34","25":"16.77","26":"17.20","27":"17.63","28":"18.06","29":"18.49","30":"18.92"},"220.00":{"1":"1.21","2":"2.42","3":"3.63","4":"4.84","5":"6.05","6":"7.26","7":"8.47","8":"9.02","9":"9.57","10":"10.12","11":"10.67","12":"11.22","13":"11.77","14":"12.32","15":"12.76","16":"13.20","17":"13.64","18":"14.08","19":"14.52","20":"14.96","21":"15.40","22":"15.84","23":"16.28","24":"16.72","25":"17.16","26":"17.60","27":"18.04","28":"18.48","29":"18.92","30":"19.36"},"225.00":{"1":"1.24","2":"2.48","3":"3.71","4":"4.95","5":"6.19","6":"7.43","7":"8.66","8":"9.23","9":"9.79","10":"10.35","11":"10.91","12":"11.48","13":"12.04","14":"12.60","15":"13.05","16":"13.50","17":"13.95","18":"14.40","19":"14.85","20":"15.30","21":"15.75","22":"16.20","23":"16.65","24":"17.10","25":"17.55","26":"18.00","27":"18.45","28":"18.90","29":"19.35","30":"19.80"},"230.00":{"1":"1.27","2":"2.53","3":"3.80","4":"5.06","5":"6.33","6":"7.59","7":"8.86","8":"9.43","9":"10.00","10":"10.58","11":"11.15","12":"11.73","13":"12.30","14":"12.88","15":"13.34","16":"13.80","17":"14.26","18":"14.72","19":"15.18","20":"15.64","21":"16.10","22":"16.56","23":"17.02","24":"17.48","25":"17.94","26":"18.40","27":"18.86","28":"19.32","29":"19.78","30":"20.24"},"235.00":{"1":"1.29","2":"2.59","3":"3.88","4":"5.17","5":"6.46","6":"7.76","7":"9.05","8":"9.64","9":"10.22","10":"10.81","11":"11.40","12":"11.99","13":"12.57","14":"13.16","15":"13.63","16":"14.10","17":"14.57","18":"15.04","19":"15.51","20":"15.98","21":"16.45","22":"16.92","23":"17.39","24":"17.86","25":"18.33","26":"18.80","27":"19.27","28":"19.74","29":"20.21","30":"20.68"},"240.00":{"1":"1.32","2":"2.64","3":"3.96","4":"5.28","5":"6.60","6":"7.92","7":"9.24","8":"9.84","9":"10.44","10":"11.04","11":"11.64","12":"12.24","13":"12.84","14":"13.44","15":"13.92","16":"14.40","17":"14.88","18":"15.36","19":"15.84","20":"16.32","21":"16.80","22":"17.28","23":"17.76","24":"18.24","25":"18.72","26":"19.20","27":"19.68","28":"20.16","29":"20.64","30":"21.12"},"245.00":{"1":"1.35","2":"2.70","3":"4.04","4":"5.39","5":"6.74","6":"8.09","7":"9.43","8":"10.05","9":"10.66","10":"11.27","11":"11.88","12":"12.50","13":"13.11","14":"13.72","15":"14.21","16":"14.70","17":"15.19","18":"15.68","19":"16.17","20":"16.66","21":"17.15","22":"17.64","23":"18.13","24":"18.62","25":"19.11","26":"19.60","27":"20.09","28":"20.58","29":"21.07","30":"21.56"},"250.00":{"1":"1.38","2":"2.75","3":"4.13","4":"5.50","5":"6.88","6":"8.25","7":"9.63","8":"10.25","9":"10.87","10":"11.50","11":"12.12","12":"12.75","13":"13.37","14":"14.00","15":"14.50","16":"15.00","17":"15.50","18":"16.00","19":"16.50","20":"17.00","21":"17.50","22":"18.00","23":"18.50","24":"19.00","25":"19.50","26":"20.00","27":"20.50","28":"21.00","29":"21.50","30":"22.00"},"255.00":{"1":"1.40","2":"2.81","3":"4.21","4":"5.61","5":"7.01","6":"8.42","7":"9.82","8":"10.46","9":"11.09","10":"11.73","11":"12.37","12":"13.01","13":"13.64","14":"14.28","15":"14.79","16":"15.30","17":"15.81","18":"16.32","19":"16.83","20":"17.34","21":"17.85","22":"18.36","23":"18.87","24":"19.38","25":"19.89","26":"20.40","27":"20.91","28":"21.42","29":"21.93","30":"22.44"},"260.00":{"1":"1.43","2":"2.86","3":"4.29","4":"5.72","5":"7.15","6":"8.58","7":"10.01","8":"10.66","9":"11.31","10":"11.96","11":"12.61","12":"13.26","13":"13.91","14":"14.56","15":"15.08","16":"15.60","17":"16.12","18":"16.64","19":"17.16","20":"17.68","21":"18.20","22":"18.72","23":"19.24","24":"19.76","25":"20.28","26":"20.80","27":"21.32","28":"21.84","29":"22.36","30":"22.88"},"265.00":{"1":"1.46","2":"2.92","3":"4.37","4":"5.83","5":"7.29","6":"8.75","7":"10.20","8":"10.87","9":"11.53","10":"12.19","11":"12.85","12":"13.52","13":"14.18","14":"14.84","15":"15.37","16":"15.90","17":"16.43","18":"16.96","19":"17.49","20":"18.02","21":"18.55","22":"19.08","23":"19.61","24":"20.14","25":"20.67","26":"21.20","27":"21.73","28":"22.26","29":"22.79","30":"23.32"},"270.00":{"1":"1.49","2":"2.97","3":"4.46","4":"5.94","5":"7.43","6":"8.91","7":"10.40","8":"11.07","9":"11.74","10":"12.42","11":"13.09","12":"13.77","13":"14.44","14":"15.12","15":"15.66","16":"16.20","17":"16.74","18":"17.28","19":"17.82","20":"18.36","21":"18.90","22":"19.44","23":"19.98","24":"20.52","25":"21.06","26":"21.60","27":"22.14","28":"22.68","29":"23.22","30":"23.76"},"275.00":{"1":"1.51","2":"3.03","3":"4.54","4":"6.05","5":"7.56","6":"9.08","7":"10.59","8":"11.28","9":"11.96","10":"12.65","11":"13.34","12":"14.03","13":"14.71","14":"15.40","15":"15.95","16":"16.50","17":"17.05","18":"17.60","19":"18.15","20":"18.70","21":"19.25","22":"19.80","23":"20.35","24":"20.90","25":"21.45","26":"22.00","27":"22.55","28":"23.10","29":"23.65","30":"24.20"},"280.00":{"1":"1.54","2":"3.08","3":"4.62","4":"6.16","5":"7.70","6":"9.24","7":"10.78","8":"11.48","9":"12.18","10":"12.88","11":"13.58","12":"14.28","13":"14.98","14":"15.68","15":"16.24","16":"16.80","17":"17.36","18":"17.92","19":"18.48","20":"19.04","21":"19.60","22":"20.16","23":"20.72","24":"21.28","25":"21.84","26":"22.40","27":"22.96","28":"23.52","29":"24.08","30":"24.64"},"285.00":{"1":"1.57","2":"3.14","3":"4.70","4":"6.27","5":"7.84","6":"9.41","7":"10.97","8":"11.69","9":"12.40","10":"13.11","11":"13.82","12":"14.54","13":"15.25","14":"15.96","15":"16.53","16":"17.10","17":"17.67","18":"18.24","19":"18.81","20":"19.38","21":"19.95","22":"20.52","23":"21.09","24":"21.66","25":"22.23","26":"22.80","27":"23.37","28":"23.94","29":"24.51","30":"25.08"},"290.00":{"1":"1.60","2":"3.19","3":"4.79","4":"6.38","5":"7.98","6":"9.57","7":"11.17","8":"11.89","9":"12.61","10":"13.34","11":"14.06","12":"14.79","13":"15.51","14":"16.24","15":"16.82","16":"17.40","17":"17.98","18":"18.56","19":"19.14","20":"19.72","21":"20.30","22":"20.88","23":"21.46","24":"22.04","25":"22.62","26":"23.20","27":"23.78","28":"24.36","29":"24.94","30":"25.52"},"295.00":{"1":"1.62","2":"3.25","3":"4.87","4":"6.49","5":"8.11","6":"9.74","7":"11.36","8":"12.10","9":"12.83","10":"13.57","11":"14.31","12":"15.05","13":"15.78","14":"16.52","15":"17.11","16":"17.70","17":"18.29","18":"18.88","19":"19.47","20":"20.06","21":"20.65","22":"21.24","23":"21.83","24":"22.42","25":"23.01","26":"23.60","27":"24.19","28":"24.78","29":"25.37","30":"25.96"},"300.00":{"1":"1.65","2":"3.30","3":"4.95","4":"6.60","5":"8.25","6":"9.90","7":"11.55","8":"12.30","9":"13.05","10":"13.80","11":"14.55","12":"15.30","13":"16.05","14":"16.80","15":"17.40","16":"18.00","17":"18.60","18":"19.20","19":"19.80","20":"20.40","21":"21.00","22":"21.60","23":"22.20","24":"22.80","25":"23.40","26":"24.00","27":"24.60","28":"25.20","29":"25.80","30":"26.40"},"305.00":{"1":"1.68","2":"3.36","3":"5.03","4":"6.71","5":"8.39","6":"10.07","7":"11.74","8":"12.51","9":"13.27","10":"14.03","11":"14.79","12":"15.56","13":"16.32","14":"17.08","15":"17.69","16":"18.30","17":"18.91","18":"19.52","19":"20.13","20":"20.74","21":"21.35","22":"21.96","23":"22.57","24":"23.18","25":"23.79","26":"24.40","27":"25.01","28":"25.62","29":"26.23","30":"26.84"},"310.00":{"1":"1.71","2":"3.41","3":"5.12","4":"6.82","5":"8.53","6":"10.23","7":"11.94","8":"12.71","9":"13.48","10":"14.26","11":"15.03","12":"15.81","13":"16.58","14":"17.36","15":"17.98","16":"18.60","17":"19.22","18":"19.84","19":"20.46","20":"21.08","21":"21.70","22":"22.32","23":"22.94","24":"23.56","25":"24.18","26":"24.80","27":"25.42","28":"26.04","29":"26.66","30":"27.28"},"315.00":{"1":"1.73","2":"3.47","3":"5.20","4":"6.93","5":"8.66","6":"10.40","7":"12.13","8":"12.92","9":"13.70","10":"14.49","11":"15.28","12":"16.07","13":"16.85","14":"17.64","15":"18.27","16":"18.90","17":"19.53","18":"20.16","19":"20.79","20":"21.42","21":"22.05","22":"22.68","23":"23.31","24":"23.94","25":"24.57","26":"25.20","27":"25.83","28":"26.46","29":"27.09","30":"27.72"},"320.00":{"1":"1.76","2":"3.52","3":"5.28","4":"7.04","5":"8.80","6":"10.56","7":"12.32","8":"13.12","9":"13.92","10":"14.72","11":"15.52","12":"16.32","13":"17.12","14":"17.92","15":"18.56","16":"19.20","17":"19.84","18":"20.48","19":"21.12","20":"21.76","21":"22.40","22":"23.04","23":"23.68","24":"24.32","25":"24.96","26":"25.60","27":"26.24","28":"26.88","29":"27.52","30":"28.16"},"325.00":{"1":"1.79","2":"3.58","3":"5.36","4":"7.15","5":"8.94","6":"10.73","7":"12.51","8":"13.33","9":"14.14","10":"14.95","11":"15.76","12":"16.58","13":"17.39","14":"18.20","15":"18.85","16":"19.50","17":"20.15","18":"20.80","19":"21.45","20":"22.10","21":"22.75","22":"23.40","23":"24.05","24":"24.70","25":"25.35","26":"26.00","27":"26.65","28":"27.30","29":"27.95","30":"28.60"},"330.00":{"1":"1.82","2":"3.63","3":"5.45","4":"7.26","5":"9.08","6":"10.89","7":"12.71","8":"13.53","9":"14.35","10":"15.18","11":"16.00","12":"16.83","13":"17.65","14":"18.48","15":"19.14","16":"19.80","17":"20.46","18":"21.12","19":"21.78","20":"22.44","21":"23.10","22":"23.76","23":"24.42","24":"25.08","25":"25.74","26":"26.40","27":"27.06","28":"27.72","29":"28.38","30":"29.04"},"335.00":{"1":"1.84","2":"3.69","3":"5.53","4":"7.37","5":"9.21","6":"11.06","7":"12.90","8":"13.74","9":"14.57","10":"15.41","11":"16.25","12":"17.09","13":"17.92","14":"18.76","15":"19.43","16":"20.10","17":"20.77","18":"21.44","19":"22.11","20":"22.78","21":"23.45","22":"24.12","23":"24.79","24":"25.46","25":"26.13","26":"26.80","27":"27.47","28":"28.14","29":"28.81","30":"29.48"},"340.00":{"1":"1.87","2":"3.74","3":"5.61","4":"7.48","5":"9.35","6":"11.22","7":"13.09","8":"13.94","9":"14.79","10":"15.64","11":"16.49","12":"17.34","13":"18.19","14":"19.04","15":"19.72","16":"20.40","17":"21.08","18":"21.76","19":"22.44","20":"23.12","21":"23.80","22":"24.48","23":"25.16","24":"25.84","25":"26.52","26":"27.20","27":"27.88","28":"28.56","29":"29.24","30":"29.92"},"345.00":{"1":"1.90","2":"3.80","3":"5.69","4":"7.59","5":"9.49","6":"11.39","7":"13.28","8":"14.15","9":"15.01","10":"15.87","11":"16.73","12":"17.60","13":"18.46","14":"19.32","15":"20.01","16":"20.70","17":"21.39","18":"22.08","19":"22.77","20":"23.46","21":"24.15","22":"24.84","23":"25.53","24":"26.22","25":"26.91","26":"27.60","27":"28.29","28":"28.98","29":"29.67","30":"30.36"},"350.00":{"1":"1.93","2":"3.85","3":"5.78","4":"7.70","5":"9.63","6":"11.55","7":"13.48","8":"14.35","9":"15.22","10":"16.10","11":"16.97","12":"17.85","13":"18.72","14":"19.60","15":"20.30","16":"21.00","17":"21.70","18":"22.40","19":"23.10","20":"23.80","21":"24.50","22":"25.20","23":"25.90","24":"26.60","25":"27.30","26":"28.00","27":"28.70","28":"29.40","29":"30.10","30":"30.80"},"355.00":{"1":"1.95","2":"3.91","3":"5.86","4":"7.81","5":"9.76","6":"11.72","7":"13.67","8":"14.56","9":"15.44","10":"16.33","11":"17.22","12":"18.11","13":"18.99","14":"19.88","15":"20.59","16":"21.30","17":"22.01","18":"22.72","19":"23.43","20":"24.14","21":"24.85","22":"25.56","23":"26.27","24":"26.98","25":"27.69","26":"28.40","27":"29.11","28":"29.82","29":"30.53","30":"31.24"},"360.00":{"1":"1.98","2":"3.96","3":"5.94","4":"7.92","5":"9.90","6":"11.88","7":"13.86","8":"14.76","9":"15.66","10":"16.56","11":"17.46","12":"18.36","13":"19.26","14":"20.16","15":"20.88","16":"21.60","17":"22.32","18":"23.04","19":"23.76","20":"24.48","21":"25.20","22":"25.92","23":"26.64","24":"27.36","25":"28.08","26":"28.80","27":"29.52","28":"30.24","29":"30.97","30":"31.68"},"365.00":{"1":"2.01","2":"4.02","3":"6.02","4":"8.03","5":"10.04","6":"12.05","7":"14.05","8":"14.97","9":"15.88","10":"16.79","11":"17.70","12":"18.62","13":"19.53","14":"20.44","15":"21.17","16":"21.90","17":"22.63","18":"23.36","19":"24.09","20":"24.82","21":"25.55","22":"26.28","23":"27.01","24":"27.74","25":"28.47","26":"29.20","27":"29.93","28":"30.66","29":"31.40","30":"32.12"},"370.00":{"1":"2.04","2":"4.07","3":"6.11","4":"8.14","5":"10.18","6":"12.21","7":"14.25","8":"15.17","9":"16.09","10":"17.02","11":"17.94","12":"18.87","13":"19.79","14":"20.72","15":"21.46","16":"22.20","17":"22.94","18":"23.68","19":"24.42","20":"25.16","21":"25.90","22":"26.64","23":"27.38","24":"28.12","25":"28.86","26":"29.60","27":"30.34","28":"31.08","29":"31.83","30":"32.56"},"375.00":{"1":"2.06","2":"4.13","3":"6.19","4":"8.25","5":"10.31","6":"12.38","7":"14.44","8":"15.38","9":"16.31","10":"17.25","11":"18.19","12":"19.13","13":"20.06","14":"21.00","15":"21.75","16":"22.50","17":"23.25","18":"24.00","19":"24.75","20":"25.50","21":"26.25","22":"27.00","23":"27.75","24":"28.50","25":"29.25","26":"30.00","27":"30.75","28":"31.50","29":"32.26","30":"33.00"},"380.00":{"1":"2.09","2":"4.18","3":"6.27","4":"8.36","5":"10.45","6":"12.54","7":"14.63","8":"15.58","9":"16.53","10":"17.48","11":"18.43","12":"19.38","13":"20.33","14":"21.28","15":"22.04","16":"22.80","17":"23.56","18":"24.32","19":"25.08","20":"25.84","21":"26.60","22":"27.36","23":"28.12","24":"28.88","25":"29.64","26":"30.40","27":"31.16","28":"31.92","29":"32.69","30":"33.44"},"385.00":{"1":"2.12","2":"4.24","3":"6.35","4":"8.47","5":"10.59","6":"12.71","7":"14.82","8":"15.79","9":"16.75","10":"17.71","11":"18.67","12":"19.64","13":"20.60","14":"21.56","15":"22.33","16":"23.10","17":"23.87","18":"24.64","19":"25.41","20":"26.18","21":"26.95","22":"27.72","23":"28.49","24":"29.26","25":"30.03","26":"30.80","27":"31.57","28":"32.34","29":"33.12","30":"33.88"},"390.00":{"1":"2.15","2":"4.29","3":"6.44","4":"8.58","5":"10.73","6":"12.87","7":"15.02","8":"15.99","9":"16.96","10":"17.94","11":"18.91","12":"19.89","13":"20.86","14":"21.84","15":"22.62","16":"23.40","17":"24.18","18":"24.96","19":"25.74","20":"26.52","21":"27.30","22":"28.08","23":"28.86","24":"29.64","25":"30.42","26":"31.20","27":"31.98","28":"32.76","29":"33.55","30":"34.32"},"395.00":{"1":"2.17","2":"4.35","3":"6.52","4":"8.69","5":"10.86","6":"13.04","7":"15.21","8":"16.20","9":"17.18","10":"18.17","11":"19.16","12":"20.15","13":"21.13","14":"22.12","15":"22.91","16":"23.70","17":"24.49","18":"25.28","19":"26.07","20":"26.86","21":"27.65","22":"28.44","23":"29.23","24":"30.02","25":"30.81","26":"31.60","27":"32.39","28":"33.18","29":"33.98","30":"34.76"},"400.00":{"1":"2.20","2":"4.40","3":"6.60","4":"8.80","5":"11.00","6":"13.20","7":"15.40","8":"16.40","9":"17.40","10":"18.40","11":"19.40","12":"20.40","13":"21.40","14":"22.40","15":"23.20","16":"24.00","17":"24.80","18":"25.60","19":"26.40","20":"27.20","21":"28.00","22":"28.80","23":"29.60","24":"30.40","25":"31.20","26":"32.00","27":"32.80","28":"33.60","29":"34.41","30":"35.20"},"405.00":{"1":"2.23","2":"4.46","3":"6.68","4":"8.91","5":"11.14","6":"13.37","7":"15.59","8":"16.61","9":"17.62","10":"18.63","11":"19.64","12":"20.66","13":"21.67","14":"22.68","15":"23.49","16":"24.30","17":"25.11","18":"25.92","19":"26.73","20":"27.54","21":"28.35","22":"29.16","23":"29.97","24":"30.78","25":"31.59","26":"32.40","27":"33.21","28":"34.02","29":"34.84","30":"35.64"},"410.00":{"1":"2.26","2":"4.51","3":"6.77","4":"9.02","5":"11.28","6":"13.53","7":"15.79","8":"16.81","9":"17.83","10":"18.86","11":"19.88","12":"20.91","13":"21.93","14":"22.96","15":"23.78","16":"24.60","17":"25.42","18":"26.24","19":"27.06","20":"27.88","21":"28.70","22":"29.52","23":"30.34","24":"31.16","25":"31.98","26":"32.80","27":"33.62","28":"34.44","29":"35.27","30":"36.08"},"415.00":{"1":"2.28","2":"4.57","3":"6.85","4":"9.13","5":"11.41","6":"13.70","7":"15.98","8":"17.02","9":"18.05","10":"19.09","11":"20.13","12":"21.17","13":"22.20","14":"23.24","15":"24.07","16":"24.90","17":"25.73","18":"26.56","19":"27.39","20":"28.22","21":"29.05","22":"29.88","23":"30.71","24":"31.54","25":"32.37","26":"33.20","27":"34.03","28":"34.86","29":"35.70","30":"36.52"},"420.00":{"1":"2.31","2":"4.62","3":"6.93","4":"9.24","5":"11.55","6":"13.86","7":"16.17","8":"17.22","9":"18.27","10":"19.32","11":"20.37","12":"21.42","13":"22.47","14":"23.52","15":"24.36","16":"25.20","17":"26.04","18":"26.88","19":"27.72","20":"28.56","21":"29.40","22":"30.24","23":"31.08","24":"31.92","25":"32.76","26":"33.60","27":"34.44","28":"35.28","29":"36.13","30":"36.96"},"425.00":{"1":"2.34","2":"4.68","3":"7.01","4":"9.35","5":"11.69","6":"14.03","7":"16.36","8":"17.43","9":"18.49","10":"19.55","11":"20.61","12":"21.68","13":"22.74","14":"23.80","15":"24.65","16":"25.50","17":"26.35","18":"27.20","19":"28.05","20":"28.90","21":"29.75","22":"30.60","23":"31.45","24":"32.30","25":"33.15","26":"34.00","27":"34.85","28":"35.70","29":"36.56","30":"37.40"},"430.00":{"1":"2.37","2":"4.73","3":"7.10","4":"9.46","5":"11.83","6":"14.19","7":"16.56","8":"17.63","9":"18.70","10":"19.78","11":"20.85","12":"21.93","13":"23.00","14":"24.08","15":"24.94","16":"25.80","17":"26.66","18":"27.52","19":"28.38","20":"29.24","21":"30.10","22":"30.96","23":"31.82","24":"32.68","25":"33.54","26":"34.40","27":"35.26","28":"36.12","29":"36.99","30":"37.84"},"435.00":{"1":"2.39","2":"4.79","3":"7.18","4":"9.57","5":"11.96","6":"14.36","7":"16.75","8":"17.84","9":"18.92","10":"20.01","11":"21.10","12":"22.19","13":"23.27","14":"24.36","15":"25.23","16":"26.10","17":"26.97","18":"27.84","19":"28.71","20":"29.58","21":"30.45","22":"31.32","23":"32.19","24":"33.06","25":"33.93","26":"34.80","27":"35.67","28":"36.54","29":"37.42","30":"38.28"},"440.00":{"1":"2.42","2":"4.84","3":"7.26","4":"9.68","5":"12.10","6":"14.52","7":"16.94","8":"18.04","9":"19.14","10":"20.24","11":"21.34","12":"22.44","13":"23.54","14":"24.64","15":"25.52","16":"26.40","17":"27.28","18":"28.16","19":"29.04","20":"29.92","21":"30.80","22":"31.68","23":"32.56","24":"33.44","25":"34.32","26":"35.20","27":"36.08","28":"36.96","29":"37.85","30":"38.72"},"445.00":{"1":"2.45","2":"4.90","3":"7.34","4":"9.79","5":"12.24","6":"14.69","7":"17.13","8":"18.25","9":"19.36","10":"20.47","11":"21.58","12":"22.70","13":"23.81","14":"24.92","15":"25.81","16":"26.70","17":"27.59","18":"28.48","19":"29.37","20":"30.26","21":"31.15","22":"32.04","23":"32.93","24":"33.82","25":"34.71","26":"35.60","27":"36.49","28":"37.38","29":"38.28","30":"39.16"},"450.00":{"1":"2.48","2":"4.95","3":"7.43","4":"9.90","5":"12.38","6":"14.85","7":"17.33","8":"18.45","9":"19.57","10":"20.70","11":"21.82","12":"22.95","13":"24.07","14":"25.20","15":"26.10","16":"27.00","17":"27.90","18":"28.80","19":"29.70","20":"30.60","21":"31.50","22":"32.40","23":"33.30","24":"34.20","25":"35.10","26":"36.00","27":"36.90","28":"37.80","29":"38.71","30":"39.60"},"455.00":{"1":"2.50","2":"5.01","3":"7.51","4":"10.01","5":"12.51","6":"15.02","7":"17.52","8":"18.66","9":"19.79","10":"20.93","11":"22.07","12":"23.21","13":"24.34","14":"25.48","15":"26.39","16":"27.30","17":"28.21","18":"29.12","19":"30.03","20":"30.94","21":"31.85","22":"32.76","23":"33.67","24":"34.58","25":"35.49","26":"36.40","27":"37.31","28":"38.22","29":"39.14","30":"40.04"},"460.00":{"1":"2.53","2":"5.06","3":"7.59","4":"10.12","5":"12.65","6":"15.18","7":"17.71","8":"18.86","9":"20.01","10":"21.16","11":"22.31","12":"23.46","13":"24.61","14":"25.76","15":"26.68","16":"27.60","17":"28.52","18":"29.44","19":"30.36","20":"31.28","21":"32.20","22":"33.12","23":"34.04","24":"34.96","25":"35.88","26":"36.80","27":"37.72","28":"38.64","29":"39.57","30":"40.48"},"465.00":{"1":"2.56","2":"5.12","3":"7.67","4":"10.23","5":"12.79","6":"15.35","7":"17.90","8":"19.07","9":"20.23","10":"21.39","11":"22.55","12":"23.72","13":"24.88","14":"26.04","15":"26.97","16":"27.90","17":"28.83","18":"29.76","19":"30.69","20":"31.62","21":"32.55","22":"33.48","23":"34.41","24":"35.34","25":"36.27","26":"37.20","27":"38.13","28":"39.06","29":"40.00","30":"40.92"},"470.00":{"1":"2.59","2":"5.17","3":"7.76","4":"10.34","5":"12.93","6":"15.51","7":"18.10","8":"19.27","9":"20.44","10":"21.62","11":"22.79","12":"23.97","13":"25.14","14":"26.32","15":"27.26","16":"28.20","17":"29.14","18":"30.08","19":"31.02","20":"31.96","21":"32.90","22":"33.84","23":"34.78","24":"35.72","25":"36.66","26":"37.60","27":"38.54","28":"39.48","29":"40.43","30":"41.36"},"475.00":{"1":"2.61","2":"5.23","3":"7.84","4":"10.45","5":"13.06","6":"15.68","7":"18.29","8":"19.48","9":"20.66","10":"21.85","11":"23.04","12":"24.23","13":"25.41","14":"26.60","15":"27.55","16":"28.50","17":"29.45","18":"30.40","19":"31.35","20":"32.30","21":"33.25","22":"34.20","23":"35.15","24":"36.10","25":"37.05","26":"38.00","27":"38.95","28":"39.90","29":"40.86","30":"41.80"},"480.00":{"1":"2.64","2":"5.28","3":"7.92","4":"10.56","5":"13.20","6":"15.84","7":"18.48","8":"19.68","9":"20.88","10":"22.08","11":"23.28","12":"24.48","13":"25.68","14":"26.88","15":"27.84","16":"28.80","17":"29.76","18":"30.72","19":"31.68","20":"32.64","21":"33.60","22":"34.56","23":"35.52","24":"36.48","25":"37.44","26":"38.40","27":"39.36","28":"40.32","29":"41.29","30":"42.24"},"485.00":{"1":"2.67","2":"5.34","3":"8.00","4":"10.67","5":"13.34","6":"16.01","7":"18.67","8":"19.89","9":"21.10","10":"22.31","11":"23.52","12":"24.74","13":"25.95","14":"27.16","15":"28.13","16":"29.10","17":"30.07","18":"31.04","19":"32.01","20":"32.98","21":"33.95","22":"34.92","23":"35.89","24":"36.86","25":"37.83","26":"38.80","27":"39.77","28":"40.74","29":"41.72","30":"42.68"},"490.00":{"1":"2.70","2":"5.39","3":"8.09","4":"10.78","5":"13.48","6":"16.17","7":"18.87","8":"20.09","9":"21.31","10":"22.54","11":"23.76","12":"24.99","13":"26.21","14":"27.44","15":"28.42","16":"29.40","17":"30.38","18":"31.36","19":"32.34","20":"33.32","21":"34.30","22":"35.28","23":"36.26","24":"37.24","25":"38.22","26":"39.20","27":"40.18","28":"41.16","29":"42.15","30":"43.12"},"495.00":{"1":"2.72","2":"5.45","3":"8.17","4":"10.89","5":"13.61","6":"16.34","7":"19.06","8":"20.30","9":"21.53","10":"22.77","11":"24.01","12":"25.25","13":"26.48","14":"27.72","15":"28.71","16":"29.70","17":"30.69","18":"31.68","19":"32.67","20":"33.66","21":"34.65","22":"35.64","23":"36.63","24":"37.62","25":"38.61","26":"39.60","27":"40.59","28":"41.58","29":"42.58","30":"43.56"},"500.00":{"1":"2.75","2":"5.50","3":"8.25","4":"11.00","5":"13.75","6":"16.50","7":"19.25","8":"20.50","9":"21.75","10":"23.00","11":"24.25","12":"25.50","13":"26.75","14":"28.00","15":"29.00","16":"30.00","17":"31.00","18":"32.00","19":"33.00","20":"34.00","21":"35.00","22":"36.00","23":"37.00","24":"38.00","25":"39.00","26":"40.00","27":"41.00","28":"42.00","29":"43.01","30":"44.00"},"505.00":{"1":"2.78","2":"5.56","3":"8.33","4":"11.11","5":"13.89","6":"16.67","7":"19.44","8":"20.71","9":"21.97","10":"23.23","11":"24.49","12":"25.76","13":"27.01","14":"28.28","15":"29.29","16":"30.30","17":"31.31","18":"32.32","19":"33.33","20":"34.34","21":"35.35","22":"36.36","23":"37.37","24":"38.38","25":"39.39","26":"40.40","27":"41.41","28":"42.42","29":"43.44","30":"44.43"},"510.00":{"1":"2.81","2":"5.61","3":"8.42","4":"11.22","5":"14.03","6":"16.83","7":"19.64","8":"20.91","9":"22.18","10":"23.46","11":"24.73","12":"26.01","13":"27.28","14":"28.56","15":"29.58","16":"30.60","17":"31.62","18":"32.64","19":"33.66","20":"34.68","21":"35.70","22":"36.72","23":"37.74","24":"38.76","25":"39.78","26":"40.80","27":"41.82","28":"42.84","29":"43.87","30":"44.87"},"515.00":{"1":"2.83","2":"5.67","3":"8.50","4":"11.33","5":"14.16","6":"17.00","7":"19.83","8":"21.12","9":"22.40","10":"23.69","11":"24.98","12":"26.27","13":"27.55","14":"28.84","15":"29.87","16":"30.90","17":"31.93","18":"32.96","19":"33.99","20":"35.02","21":"36.05","22":"37.08","23":"38.11","24":"39.14","25":"40.17","26":"41.20","27":"42.23","28":"43.26","29":"44.30","30":"45.31"},"520.00":{"1":"2.86","2":"5.72","3":"8.58","4":"11.44","5":"14.30","6":"17.16","7":"20.02","8":"21.32","9":"22.62","10":"23.92","11":"25.22","12":"26.52","13":"27.82","14":"29.12","15":"30.16","16":"31.20","17":"32.24","18":"33.28","19":"34.32","20":"35.36","21":"36.40","22":"37.44","23":"38.48","24":"39.52","25":"40.56","26":"41.60","27":"42.64","28":"43.68","29":"44.73","30":"45.75"},"525.00":{"1":"2.89","2":"5.78","3":"8.66","4":"11.55","5":"14.44","6":"17.33","7":"20.21","8":"21.53","9":"22.84","10":"24.15","11":"25.46","12":"26.78","13":"28.08","14":"29.40","15":"30.45","16":"31.50","17":"32.55","18":"33.60","19":"34.65","20":"35.70","21":"36.75","22":"37.80","23":"38.85","24":"39.90","25":"40.95","26":"42.00","27":"43.05","28":"44.10","29":"45.16","30":"46.19"},"530.00":{"1":"2.92","2":"5.83","3":"8.75","4":"11.66","5":"14.58","6":"17.49","7":"20.41","8":"21.73","9":"23.05","10":"24.38","11":"25.70","12":"27.03","13":"28.35","14":"29.68","15":"30.74","16":"31.80","17":"32.86","18":"33.92","19":"34.98","20":"36.04","21":"37.10","22":"38.16","23":"39.22","24":"40.28","25":"41.34","26":"42.40","27":"43.46","28":"44.52","29":"45.59","30":"46.63"},"535.00":{"1":"2.94","2":"5.89","3":"8.83","4":"11.77","5":"14.71","6":"17.66","7":"20.60","8":"21.94","9":"23.27","10":"24.61","11":"25.95","12":"27.29","13":"28.62","14":"29.96","15":"31.03","16":"32.10","17":"33.17","18":"34.24","19":"35.31","20":"36.38","21":"37.45","22":"38.52","23":"39.59","24":"40.66","25":"41.73","26":"42.80","27":"43.87","28":"44.94","29":"46.02","30":"47.07"},"540.00":{"1":"2.97","2":"5.94","3":"8.91","4":"11.88","5":"14.85","6":"17.82","7":"20.79","8":"22.14","9":"23.49","10":"24.84","11":"26.19","12":"27.54","13":"28.89","14":"30.24","15":"31.32","16":"32.40","17":"33.48","18":"34.56","19":"35.64","20":"36.72","21":"37.80","22":"38.88","23":"39.96","24":"41.04","25":"42.12","26":"43.20","27":"44.28","28":"45.36","29":"46.45","30":"47.51"},"545.00":{"1":"3.00","2":"6.00","3":"8.99","4":"11.99","5":"14.99","6":"17.99","7":"20.98","8":"22.35","9":"23.71","10":"25.07","11":"26.43","12":"27.80","13":"29.15","14":"30.52","15":"31.61","16":"32.70","17":"33.79","18":"34.88","19":"35.97","20":"37.06","21":"38.15","22":"39.24","23":"40.33","24":"41.42","25":"42.51","26":"43.60","27":"44.69","28":"45.78","29":"46.88","30":"47.95"},"550.00":{"1":"3.03","2":"6.05","3":"9.08","4":"12.10","5":"15.13","6":"18.15","7":"21.18","8":"22.55","9":"23.92","10":"25.30","11":"26.67","12":"28.05","13":"29.42","14":"30.80","15":"31.90","16":"33.00","17":"34.10","18":"35.20","19":"36.30","20":"37.40","21":"38.50","22":"39.60","23":"40.70","24":"41.80","25":"42.90","26":"44.00","27":"45.10","28":"46.20","29":"47.31","30":"48.39"},"555.00":{"1":"3.05","2":"6.11","3":"9.16","4":"12.21","5":"15.26","6":"18.32","7":"21.37","8":"22.76","9":"24.14","10":"25.53","11":"26.92","12":"28.31","13":"29.69","14":"31.08","15":"32.19","16":"33.30","17":"34.41","18":"35.52","19":"36.63","20":"37.74","21":"38.85","22":"39.96","23":"41.07","24":"42.18","25":"43.29","26":"44.40","27":"45.51","28":"46.62","29":"47.74","30":"48.83"},"560.00":{"1":"3.08","2":"6.16","3":"9.24","4":"12.32","5":"15.40","6":"18.48","7":"21.56","8":"22.96","9":"24.36","10":"25.76","11":"27.16","12":"28.56","13":"29.96","14":"31.36","15":"32.48","16":"33.60","17":"34.72","18":"35.84","19":"36.96","20":"38.08","21":"39.20","22":"40.32","23":"41.43","24":"42.56","25":"43.68","26":"44.80","27":"45.92","28":"47.04","29":"48.17","30":"49.27"},"565.00":{"1":"3.11","2":"6.22","3":"9.32","4":"12.43","5":"15.54","6":"18.65","7":"21.75","8":"23.17","9":"24.58","10":"25.99","11":"27.40","12":"28.82","13":"30.22","14":"31.64","15":"32.77","16":"33.90","17":"35.03","18":"36.16","19":"37.29","20":"38.42","21":"39.55","22":"40.68","23":"41.80","24":"42.94","25":"44.07","26":"45.20","27":"46.33","28":"47.46","29":"48.60","30":"49.71"},"570.00":{"1":"3.14","2":"6.27","3":"9.41","4":"12.54","5":"15.68","6":"18.81","7":"21.95","8":"23.37","9":"24.79","10":"26.22","11":"27.64","12":"29.07","13":"30.49","14":"31.92","15":"33.06","16":"34.20","17":"35.34","18":"36.48","19":"37.62","20":"38.76","21":"39.90","22":"41.04","23":"42.17","24":"43.32","25":"44.46","26":"45.60","27":"46.74","28":"47.88","29":"49.03","30":"50.15"},"575.00":{"1":"3.16","2":"6.33","3":"9.49","4":"12.65","5":"15.81","6":"18.98","7":"22.14","8":"23.58","9":"25.01","10":"26.45","11":"27.89","12":"29.33","13":"30.76","14":"32.20","15":"33.35","16":"34.50","17":"35.65","18":"36.80","19":"37.95","20":"39.10","21":"40.25","22":"41.40","23":"42.54","24":"43.70","25":"44.85","26":"46.00","27":"47.15","28":"48.30","29":"49.46","30":"50.59"},"580.00":{"1":"3.19","2":"6.38","3":"9.57","4":"12.76","5":"15.95","6":"19.14","7":"22.33","8":"23.78","9":"25.23","10":"26.68","11":"28.13","12":"29.58","13":"31.03","14":"32.48","15":"33.64","16":"34.80","17":"35.96","18":"37.12","19":"38.28","20":"39.44","21":"40.60","22":"41.76","23":"42.91","24":"44.08","25":"45.24","26":"46.40","27":"47.56","28":"48.72","29":"49.89","30":"51.03"},"585.00":{"1":"3.22","2":"6.44","3":"9.65","4":"12.87","5":"16.09","6":"19.31","7":"22.52","8":"23.99","9":"25.45","10":"26.91","11":"28.37","12":"29.84","13":"31.29","14":"32.76","15":"33.93","16":"35.10","17":"36.27","18":"37.44","19":"38.61","20":"39.78","21":"40.95","22":"42.12","23":"43.28","24":"44.46","25":"45.63","26":"46.80","27":"47.97","28":"49.14","29":"50.32","30":"51.47"},"590.00":{"1":"3.25","2":"6.49","3":"9.74","4":"12.98","5":"16.23","6":"19.47","7":"22.72","8":"24.19","9":"25.66","10":"27.14","11":"28.61","12":"30.09","13":"31.56","14":"33.04","15":"34.22","16":"35.40","17":"36.58","18":"37.76","19":"38.94","20":"40.12","21":"41.30","22":"42.48","23":"43.65","24":"44.84","25":"46.02","26":"47.20","27":"48.38","28":"49.56","29":"50.75","30":"51.91"},"595.00":{"1":"3.27","2":"6.55","3":"9.82","4":"13.09","5":"16.36","6":"19.64","7":"22.91","8":"24.40","9":"25.88","10":"27.37","11":"28.86","12":"30.35","13":"31.83","14":"33.32","15":"34.51","16":"35.70","17":"36.89","18":"38.08","19":"39.27","20":"40.46","21":"41.65","22":"42.84","23":"44.02","24":"45.22","25":"46.41","26":"47.60","27":"48.79","28":"49.98","29":"51.18","30":"52.35"},"600.00":{"1":"3.30","2":"6.60","3":"9.90","4":"13.20","5":"16.50","6":"19.80","7":"23.10","8":"24.60","9":"26.10","10":"27.60","11":"29.10","12":"30.60","13":"32.10","14":"33.60","15":"34.80","16":"36.00","17":"37.20","18":"38.40","19":"39.60","20":"40.80","21":"42.00","22":"43.20","23":"44.39","24":"45.60","25":"46.80","26":"48.00","27":"49.20","28":"50.40","29":"51.61","30":"52.79"},"605.00":{"1":"3.33","2":"6.66","3":"9.98","4":"13.31","5":"16.64","6":"19.97","7":"23.29","8":"24.81","9":"26.32","10":"27.83","11":"29.34","12":"30.86","13":"32.36","14":"33.88","15":"35.09","16":"36.30","17":"37.51","18":"38.72","19":"39.93","20":"41.14","21":"42.35","22":"43.56","23":"44.76","24":"45.98","25":"47.19","26":"48.40","27":"49.61","28":"50.82","29":"52.04","30":"53.23"},"610.00":{"1":"3.36","2":"6.71","3":"10.07","4":"13.42","5":"16.78","6":"20.13","7":"23.49","8":"25.01","9":"26.53","10":"28.06","11":"29.58","12":"31.11","13":"32.63","14":"34.16","15":"35.38","16":"36.60","17":"37.82","18":"39.04","19":"40.26","20":"41.48","21":"42.70","22":"43.92","23":"45.13","24":"46.36","25":"47.58","26":"48.80","27":"50.02","28":"51.24","29":"52.47","30":"53.67"},"615.00":{"1":"3.38","2":"6.77","3":"10.15","4":"13.53","5":"16.91","6":"20.30","7":"23.68","8":"25.22","9":"26.75","10":"28.29","11":"29.83","12":"31.37","13":"32.90","14":"34.44","15":"35.67","16":"36.90","17":"38.13","18":"39.36","19":"40.59","20":"41.82","21":"43.05","22":"44.28","23":"45.50","24":"46.74","25":"47.97","26":"49.20","27":"50.43","28":"51.66","29":"52.90","30":"54.11"},"620.00":{"1":"3.41","2":"6.82","3":"10.23","4":"13.64","5":"17.05","6":"20.46","7":"23.87","8":"25.42","9":"26.97","10":"28.52","11":"30.07","12":"31.62","13":"33.17","14":"34.72","15":"35.96","16":"37.20","17":"38.44","18":"39.68","19":"40.92","20":"42.16","21":"43.40","22":"44.64","23":"45.87","24":"47.12","25":"48.36","26":"49.60","27":"50.84","28":"52.08","29":"53.33","30":"54.55"},"625.00":{"1":"3.44","2":"6.88","3":"10.31","4":"13.75","5":"17.19","6":"20.63","7":"24.06","8":"25.63","9":"27.19","10":"28.75","11":"30.31","12":"31.88","13":"33.43","14":"35.00","15":"36.25","16":"37.50","17":"38.75","18":"40.01","19":"41.25","20":"42.50","21":"43.75","22":"45.00","23":"46.24","24":"47.51","25":"48.75","26":"50.00","27":"51.25","28":"52.50","29":"53.76","30":"54.99"},"630.00":{"1":"3.47","2":"6.93","3":"10.40","4":"13.86","5":"17.33","6":"20.79","7":"24.26","8":"25.83","9":"27.40","10":"28.98","11":"30.55","12":"32.13","13":"33.70","14":"35.28","15":"36.54","16":"37.80","17":"39.06","18":"40.33","19":"41.58","20":"42.84","21":"44.10","22":"45.36","23":"46.61","24":"47.89","25":"49.14","26":"50.40","27":"51.66","28":"52.92","29":"54.19","30":"55.43"},"635.00":{"1":"3.49","2":"6.99","3":"10.48","4":"13.97","5":"17.46","6":"20.96","7":"24.45","8":"26.04","9":"27.62","10":"29.21","11":"30.80","12":"32.39","13":"33.97","14":"35.56","15":"36.83","16":"38.10","17":"39.37","18":"40.65","19":"41.91","20":"43.18","21":"44.45","22":"45.72","23":"46.98","24":"48.27","25":"49.53","26":"50.80","27":"52.07","28":"53.34","29":"54.62","30":"55.87"},"640.00":{"1":"3.52","2":"7.04","3":"10.56","4":"14.08","5":"17.60","6":"21.12","7":"24.64","8":"26.24","9":"27.84","10":"29.44","11":"31.04","12":"32.64","13":"34.24","14":"35.84","15":"37.12","16":"38.40","17":"39.68","18":"40.97","19":"42.24","20":"43.52","21":"44.80","22":"46.08","23":"47.35","24":"48.65","25":"49.92","26":"51.20","27":"52.48","28":"53.76","29":"55.05","30":"56.31"},"645.00":{"1":"3.55","2":"7.10","3":"10.64","4":"14.19","5":"17.74","6":"21.29","7":"24.83","8":"26.45","9":"28.06","10":"29.67","11":"31.28","12":"32.90","13":"34.50","14":"36.12","15":"37.41","16":"38.70","17":"39.99","18":"41.29","19":"42.57","20":"43.86","21":"45.15","22":"46.44","23":"47.72","24":"49.03","25":"50.31","26":"51.60","27":"52.89","28":"54.18","29":"55.48","30":"56.75"},"650.00":{"1":"3.58","2":"7.15","3":"10.73","4":"14.30","5":"17.88","6":"21.45","7":"25.03","8":"26.65","9":"28.27","10":"29.90","11":"31.52","12":"33.15","13":"34.77","14":"36.40","15":"37.70","16":"39.00","17":"40.30","18":"41.61","19":"42.90","20":"44.20","21":"45.50","22":"46.80","23":"48.09","24":"49.41","25":"50.70","26":"52.00","27":"53.30","28":"54.60","29":"55.91","30":"57.19"},"655.00":{"1":"3.60","2":"7.21","3":"10.81","4":"14.41","5":"18.01","6":"21.62","7":"25.22","8":"26.86","9":"28.49","10":"30.13","11":"31.77","12":"33.41","13":"35.04","14":"36.68","15":"37.99","16":"39.30","17":"40.61","18":"41.93","19":"43.23","20":"44.54","21":"45.85","22":"47.16","23":"48.46","24":"49.79","25":"51.09","26":"52.40","27":"53.71","28":"55.02","29":"56.34","30":"57.63"},"660.00":{"1":"3.63","2":"7.26","3":"10.89","4":"14.52","5":"18.15","6":"21.78","7":"25.41","8":"27.06","9":"28.71","10":"30.36","11":"32.01","12":"33.66","13":"35.31","14":"36.96","15":"38.28","16":"39.60","17":"40.92","18":"42.25","19":"43.56","20":"44.88","21":"46.20","22":"47.52","23":"48.83","24":"50.17","25":"51.48","26":"52.80","27":"54.12","28":"55.44","29":"56.77","30":"58.07"},"665.00":{"1":"3.66","2":"7.32","3":"10.97","4":"14.63","5":"18.29","6":"21.95","7":"25.60","8":"27.27","9":"28.93","10":"30.59","11":"32.25","12":"33.92","13":"35.57","14":"37.24","15":"38.57","16":"39.90","17":"41.23","18":"42.57","19":"43.89","20":"45.22","21":"46.55","22":"47.88","23":"49.20","24":"50.55","25":"51.87","26":"53.20","27":"54.53","28":"55.86","29":"57.20","30":"58.51"},"670.00":{"1":"3.69","2":"7.37","3":"11.06","4":"14.74","5":"18.43","6":"22.11","7":"25.80","8":"27.47","9":"29.14","10":"30.82","11":"32.49","12":"34.17","13":"35.84","14":"37.52","15":"38.86","16":"40.20","17":"41.54","18":"42.89","19":"44.22","20":"45.56","21":"46.90","22":"48.24","23":"49.57","24":"50.93","25":"52.26","26":"53.60","27":"54.94","28":"56.28","29":"57.63","30":"58.95"},"675.00":{"1":"3.71","2":"7.43","3":"11.14","4":"14.85","5":"18.56","6":"22.28","7":"25.99","8":"27.68","9":"29.36","10":"31.05","11":"32.74","12":"34.43","13":"36.11","14":"37.80","15":"39.15","16":"40.50","17":"41.85","18":"43.21","19":"44.55","20":"45.90","21":"47.25","22":"48.60","23":"49.94","24":"51.31","25":"52.65","26":"54.00","27":"55.35","28":"56.70","29":"58.06","30":"59.39"},"680.00":{"1":"3.74","2":"7.48","3":"11.22","4":"14.96","5":"18.70","6":"22.44","7":"26.18","8":"27.88","9":"29.58","10":"31.28","11":"32.98","12":"34.68","13":"36.38","14":"38.08","15":"39.44","16":"40.80","17":"42.16","18":"43.53","19":"44.88","20":"46.24","21":"47.60","22":"48.96","23":"50.31","24":"51.69","25":"53.04","26":"54.40","27":"55.76","28":"57.12","29":"58.49","30":"59.83"},"685.00":{"1":"3.77","2":"7.54","3":"11.30","4":"15.07","5":"18.84","6":"22.61","7":"26.37","8":"28.09","9":"29.80","10":"31.51","11":"33.22","12":"34.94","13":"36.64","14":"38.36","15":"39.73","16":"41.10","17":"42.47","18":"43.85","19":"45.21","20":"46.58","21":"47.95","22":"49.32","23":"50.68","24":"52.07","25":"53.43","26":"54.80","27":"56.17","28":"57.54","29":"58.92","30":"60.27"},"690.00":{"1":"3.80","2":"7.59","3":"11.39","4":"15.18","5":"18.98","6":"22.77","7":"26.57","8":"28.29","9":"30.01","10":"31.74","11":"33.46","12":"35.19","13":"36.91","14":"38.64","15":"40.02","16":"41.40","17":"42.78","18":"44.17","19":"45.54","20":"46.92","21":"48.30","22":"49.68","23":"51.05","24":"52.45","25":"53.82","26":"55.20","27":"56.58","28":"57.96","29":"59.35","30":"60.71"},"695.00":{"1":"3.82","2":"7.65","3":"11.47","4":"15.29","5":"19.11","6":"22.94","7":"26.76","8":"28.50","9":"30.23","10":"31.97","11":"33.71","12":"35.45","13":"37.18","14":"38.92","15":"40.31","16":"41.70","17":"43.09","18":"44.49","19":"45.87","20":"47.26","21":"48.65","22":"50.04","23":"51.42","24":"52.83","25":"54.21","26":"55.60","27":"56.99","28":"58.38","29":"59.78","30":"61.15"},"700.00":{"1":"3.85","2":"7.70","3":"11.55","4":"15.40","5":"19.25","6":"23.10","7":"26.95","8":"28.70","9":"30.45","10":"32.20","11":"33.95","12":"35.70","13":"37.45","14":"39.20","15":"40.60","16":"42.00","17":"43.40","18":"44.81","19":"46.20","20":"47.60","21":"49.00","22":"50.40","23":"51.79","24":"53.21","25":"54.60","26":"56.00","27":"57.40","28":"58.80","29":"60.21","30":"61.59"}} }, fee_types: { 1: 'principal', 2: 'loan_fee', 3: 'late_fee', 4: 'extension_fee', 5: 'penalty', 41: 'receivable_extension_fee', 51: 'interest_fee', 69: 'payout_fee', 85: 'cash_fee', 168: 'registration_fee', 257: 'late_fee_delay', 259: 'late_fee_delay', 261: 'late_fee_delay', 335: 'court_fee', 360: 'sale_fee', 461: 'late_fee_delay', 466: 'court_fee', }, promotions: { 251: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if ((bag[799] == 0 && (bag[-3] <= 425 && (bag[1071] != 321359 && bag[190] != 191)))) { bag['addDiscountPercent'](2, 100); bag['stopProcessing'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, }, loanlimit: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Stage (function () { // Group: Group if ((bag[799] == 0 && (toDate(bag[6054]).getTime() < (1714206835868-7776000000) || [4].indexOf(parseInt(bag[2538])) === -1))) { bag['setIncomeVerifyLimit'](1); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Income Verify Limit if (bag[799] > 0) { bag['setIncomeVerifyLimit'](1); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (bag[799] == 0) { bag['setVisibleLimit'](425); bag['setAvailableLimit'](700); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (bag[799] == 1) { bag['setVisibleLimit'](500); bag['setAvailableLimit'](500); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (bag[799] == 2) { bag['setVisibleLimit'](600); bag['setAvailableLimit'](600); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (bag[799] >= 3) { bag['setVisibleLimit'](700); bag['setAvailableLimit'](700); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: Helper check (function () { // Group: Group if (bag[5875] > 0) { bag['setAvailableLimit'](0); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, freshBagLimit: function (bag) { var n = { _available_limit: null, _day_lower_bound: null, _visible_limit: null, _day_limit: null, _available_day_limit: null, _lowerbound: null, _income_verify_limit: null, _reject_message: null, _slider_default: null, setSliderDefault: function (amount, term, product) { if (Number.isInteger(amount) && Number.isInteger(term) && Number.isInteger(product)) { this._slider_default = { "amount" : parseFloat(amount).toFixed(2), "term" : parseFloat(term).toFixed(0), "default_product" : product }; } }, setIncomeVerifyLimit: function (limit) { this._income_verify_limit = limit; }, setLimit: function (limit) { this._visible_limit = limit; }, setVisibleLimit: function (limit) { this._visible_limit = limit; }, setAvailableLimit: function (limit) { this._available_limit = limit; }, setHardLimit: function (limit) { this._available_limit = limit; }, getRegistrationField: function (field) { return this[field] || 0; }, getAmount: function () { return bag[-3]; }, getMaximumRepayableAmount: function () { return bag[-22]; }, setDayLowerBound: function (amount) { this._day_lower_bound = amount; }, setDayLimit: function (limit) { this._day_limit = limit; }, setAvailableDayLimit: function (limit) { this._available_day_limit = limit; }, setInstallmentsCount: function (limit) { this._day_limit = limit; }, getInstallmentsCount: function (limit) { return this._day_limit; }, setRejectLoan: function (message) { this._reject_message = message; }, setExtensionLimit: function (limit) { this._extension_limit = limit; }, setLowerBound: function (limit) { this._lowerbound = limit; }, getMonthlyPayment: function (initialPrincipal, annualInterestRate, term) { var annualInterestRate = annualInterestRate / 100; var monthlyInterestRate = annualInterestRate / 12; var divident = initialPrincipal * monthlyInterestRate; var divisor = 1 - (1 / Math.pow((1 + monthlyInterestRate), term)); return divident / divisor; }, getOverpaymentCoefficient: function (annualInterestRate, term) { var initialPrincipal = 1000; var monthlyPayment = this.getMonthlyPayment(initialPrincipal, annualInterestRate, term); var totalRepayableAmount = monthlyPayment * term; return totalRepayableAmount / initialPrincipal; }, getInterestRateApproximationFromAnnuity: function (termMonths) { var termDays = termMonths * 30; var constant = 1.000018; var resultBase = constant + (termDays * 0.0007 + 1) / termMonths; var resultLog = Math.log2(1 + 1 / termMonths); resultBase = Math.pow(resultBase, (1 / resultLog)) - 1; var interestRateApproximationFromAnnuity = ((Math.pow(resultBase, resultLog) - constant) * 12) * 100; var flooredResult = Math.floor(interestRateApproximationFromAnnuity * 100) / 100; return flooredResult; }, calculateTermUpperLimit: function (amount, maxRepayable, interest) { let monthlyInterest = (interest/100) / 12; return (isNaN(Math.ceil(Math.log(1 / (1 - ((amount * monthlyInterest) / maxRepayable))) / Math.log1p(monthlyInterest))) ? 0 : Math.ceil(Math.log(1 / (1 - ((amount * monthlyInterest) / maxRepayable))) / Math.log1p(monthlyInterest))); }, }; for (var id in bag) { if (!(id in n)) { n[id] = bag[id]; } } if ( ! (-8 in n)) { n[-8] = 88; } n["round"] = this.round return n; }, filterAvailableTerms: function (bag, checkFunction) { var limits = this.evaluateLimit(bag); var lowestAvailableTerm = null; for (var index = 0; index < limits.terms.length; index++) { var t = limits.terms[index]; bag['-2'] = t; var currentTermLimits = this.evaluateLimit(bag); if (checkFunction) { if (checkFunction(currentTermLimits)) { lowestAvailableTerm = t; break; } } else if (currentTermLimits.amounts_available.length > 0) { lowestAvailableTerm = t; break; } } return limits.terms.slice(limits.terms.indexOf(lowestAvailableTerm)); }, evaluateLimit: function (bag) { var finalAmounts_available = []; var finalAmounts_visible = []; var finalDays = []; var finalDays_available = []; var finalExtDays = []; var ibag = this.freshBagLimit(bag); var result = this.loanlimit.evaluate(ibag); this.pricelists[1].buildDimension(bag); this.pricelists[2].buildDimension(bag); this.pricelists[4].buildDimension(bag); for (var i = 0; i < this.pricelists[1].amounts.length; i++) { var amn = this.pricelists[1].amounts[i]; if ((ibag._available_limit == null || parseFloat(amn) <= ibag._available_limit) && (ibag._lowerbound == null || parseFloat(amn) >= ibag._lowerbound)) { finalAmounts_available.push(parseFloat(amn).toFixed(2)); } if ((ibag._visible_limit == null || parseFloat(amn) <= ibag._visible_limit) && (ibag._lowerbound == null || parseFloat(amn) >= ibag._lowerbound)) { finalAmounts_visible.push(parseFloat(amn).toFixed(2)); } } for (var i = 0; i < this.pricelists[1].terms.length; i++) { var day = this.pricelists[1].terms[i]; if ((ibag._day_limit == null || parseFloat(day) <= ibag._day_limit) && (ibag._day_lower_bound == null || parseFloat(day) >= ibag._day_lower_bound)) { finalDays.push(parseFloat(day).toFixed(0)); } if ((ibag._available_day_limit == null || parseFloat(day) <= ibag._available_day_limit) && (ibag._day_lower_bound == null || parseFloat(day) >= ibag._day_lower_bound)) { finalDays_available.push(parseFloat(day).toFixed(0)); } } for (var i = 0; i < this.pricelists[4].terms.length; i++) { var day = this.pricelists[4].terms[i]; if (ibag._extension_limit == null || parseFloat(day) <= ibag._extension_limit) { finalExtDays.push(parseFloat(day).toFixed(0)) } } return { 'pricelist-amount-limit': ibag._visible_limit, 'pricelist-amount-hard-limit': ibag._available_limit, 'pricelist-amount-lower-bound': ibag._lowerbound, 'pricelist-day-limit': ibag._day_limit, 'pricelist-available-day-limit': ibag._available_day_limit, 'pricelist-income-verify-limit': ibag._income_verify_limit, 'pricelist-day-lower-bound': ibag._day_lower_bound, 'reject_message': ibag._reject_message, amounts_available: finalAmounts_available, amounts_visible: finalAmounts_visible, terms: finalDays, terms_available: finalDays_available, extterms: finalExtDays, slider_default: ibag._slider_default } }, prolongPermissionRules: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: Prohibit prolonging If all products open (function () { // Group: Group if ((bag[3251] == 1 && (bag[3252] == 1 && bag['3253'] == 1))) { bag['prohibitProlong']('Has all products open'); bag['prohibitProlongToInstallment']('Has all products open'); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: OLD VERSION OF PROLONGING=>HAS OPEN PD PROLONG TO CRL (function () { // Group: PD --> CRL FL BEFORE DUEDATE if (([1,3,4].indexOf(parseInt(bag[460])) !== -1 && ((((bag[802] < 31 && bag[2788] >= 50) && [1].indexOf(bag[2438] ? 1 : 0) !== -1) && bag[3251] == 1) && bag[3252] == 0))) { bag['prohibitProlong'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: PD --> CRL FL AFTER DUEDATE if (([1,3,4].indexOf(parseInt(bag[460])) !== -1 && (((((bag[802] > 0 && bag[802] < 31) && bag[2788] >= 50) && [1].indexOf(bag[2438] ? 1 : 0) !== -1) && bag[3251] == 1) && bag[3252] == 0))) { bag['prohibitProlong'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: PD --> CRL CL BEFORE DUEDATE if (([1,3,4].indexOf(parseInt(bag[460])) !== -1 && ((((bag[802] < 31 && bag[3252] == 0) && bag[2788] >= 50) && [0].indexOf(bag[2438] ? 1 : 0) !== -1) && bag[3251] == 1))) { bag['prohibitProlong'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: NEW VERSION OF PROLONGING to IL (function () { // Group: PDL if ((bag['3141'] == 1 && ([1,3,4].indexOf(parseInt(bag['460'])) !== -1 && (bag['2788'] >= 50 && bag[802] < 31)))) { bag['prohibitProlongToInstallment'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: NEW VERSION OF PROLONGING IL -> IL (function () { // Group: IL if ((bag['3141'] == 2 && ([1].indexOf(parseInt(bag[460])) !== -1 && (bag['2788'] >= 50 && bag[802] < 31)))) { bag['prohibitProlongToInstallment'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: NEW VERSION OF PROLONGING - TO CRL -> IL (function () { // Group: CRL if ((bag['3141'] == 3 && ([17,1,4].indexOf(parseInt(bag[460])) !== -1 && (bag['2788'] >= 50 && bag['3353'] < 31)))) { bag['prohibitProlongToInstallment'](null); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; } }, freshBagProlongPermissionRule: function (bag) { var n = { _loanProlongPermitted: false, _loanProlongPermittedToPayday: false, _loanProlongPermittedToInstallment: false, _loanProlongPermittedToCreditline: false, _errorMessage: null, _errorMessageProlongToPayday: null, _errorMessageProlongToInstallment: null, _errorMessageProlongToCreditline: null, _loanSettingId: null, _feetypes: [], allowProlong: function () { this._loanProlongPermitted = true; this._errorMessage = null; }, allowProlongToPayday: function () { this._loanProlongPermittedToPayday = true; this._errorMessageProlongToPayday = null; }, allowProlongToInstallment: function () { this._loanProlongPermittedToInstallment = true; this._errorMessageProlongToInstallment = null; }, allowProlongToCreditline: function () { this._loanProlongPermittedToCreditline = true; this._errorMessageProlongToCreditline = null; }, prohibitProlong: function (msg) { this._loanProlongPermitted = false; this._errorMessage = msg; }, setLoanSettings: function (id) { this._loanSettingId = id; }, prohibitProlongToPayday: function (msg) { this._loanProlongPermittedToPayday = false; this._errorMessageProlongToPayday = msg; }, prohibitProlongToInstallment: function (msg) { this._loanProlongPermittedToInstallment = false; this._errorMessageProlongToInstallment = msg; }, prohibitProlongToCreditline: function (msg) { this._loanProlongPermittedToCreditline = false; this._errorMessageProlongToCreditline = msg; }, feetypeToNewLoan: function (feetype, percentage, maxvalue) { this._feetypes.push({ "feetype": feetype, "percentage": percentage, "maxvalue": maxvalue }); }, hasLoanOpenInAllLenders: function () { return bag[-33]; }, isRequestForLoanFromPlaton: function () { return bag["is-backend"] || false; }, isRequestForLoanFromClientzone: function () { return !bag["is-backend"]; }, }; for (var id in bag) { if ((typeof bag[id] === 'string') && !isNaN(bag[id]) && isFinite(bag[id]) && typeof bag[id] !== "boolean") { bag[id] = parseFloat(bag[id]); } if (!(id in n)) { n[id] = bag[id]; } } return n; }, evaluateProlongPermisson: function (bag) { var ibag = this.freshBagProlongPermissionRule(bag); var result = this.prolongPermissionRules.evaluate(ibag); return { 'loan-prolong-permitted': ibag._loanProlongPermitted, 'loan-prolong-permitted-to-payday': ibag._loanProlongPermittedToPayday, 'loan-prolong-permitted-to-installment': ibag._loanProlongPermittedToInstallment, 'loan-prolong-permitted-to-creditline': ibag._loanProlongPermittedToCreditline, 'loan-prolong-error': ibag._errorMessage, 'loan-prolong-to-payday-error': ibag._errorMessageProlongToPayday, 'loan-prolong-to-installment-error': ibag._errorMessageProlongToInstallment, 'loan-prolong-to-creditline-error': ibag._errorMessageProlongToCreditline, 'prolong-loan-setting-id': ibag._loanSettingId, 'loan-feetype-mapping': ibag._feetypes } }, evaluateExtensionPromotions: function (now, bag, values) { var ibag = {}; var result = null; var existingpromo = null; var percentpromo = null; var percentpromos = []; var usedPromotions = []; if (bag['existing-promotions']) { var existingPromos = bag['existing-promotions'].sort(function (a, b) { return b.priority - a.priority; }); ibag = this.freshBag(bag, null); for (var i = 0; i < existingPromos.length; i++) { existingpromo = existingPromos[i]; if (existingpromo['type'] == 'percent') { percentpromo = { 'amount': parseFloat(existingpromo['amount']), 'id': existingpromo['promoId'] }; if (existingpromo['installmentIndex'] !== undefined) { // installment index can be 0 and then it wouldnt go in percentpromo['installment_index'] = existingpromo['installmentIndex'] + 1; // + 1 because for promostaging the first installment is index 1 and not 0 } if (!percentpromos[existingpromo['feeTypeId']]) { percentpromos[existingpromo['feeTypeId']] = []; } percentpromos[existingpromo['feeTypeId']].push(percentpromo); usedPromotions.push(existingpromo['promoId'].toString()); } } ibag['discounts_per'] = percentpromos; this.fillDiscounts(ibag, values); } }, extensionPermissionRules: { evaluate: function (bag) { var vars = {}; var control = { canceled: false, quit: false }; bag['exit'] = function() { control.canceled = true; }; bag['stopProcessing'] = function() { bag['exit'](); control.quit = true; }; bag['skip'] = function() { control.skip = true; }; control.skip = false; // Stage: SET-3547 Allow ext for all (function () { // Group: Group if (bag['1217'] !== null) { bag['allowExtension'](); bag['exit'](); if (control.canceled) return; } else { bag['allowExtension'](); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; control.skip = false; // Stage: Stage (function () { // Group: Prohibit for bailiff status if ((([49,50,51,52,55,124,159,160,163,164,165,166,167,597,598].indexOf(parseInt(bag[2593])) !== -1 || [7].indexOf(parseInt(bag[460])) !== -1) || bag[802] > 60)) { bag['prohibitExtension']('Max delay reached'); bag['exit'](); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (true) { vars['diff'] = (bag[423] - (bag[4190] + bag[-11])); if (control.canceled) return; } if (control.canceled || control.skip) return; // Group: Group if (vars['diff'] < 0) { bag['prohibitExtension']('Fee limit reached'); bag['exit'](); if (control.canceled) return; } else { bag['allowExtension'](); if (control.canceled) return; } if (control.canceled || control.skip) return; })(); if (control.canceled) return control; return control; }, freshBag: function (bag, extensionPrice) { var n = { _loanExtensionPermitted: false, _errorMessage: null, allowExtension: function () { this._loanExtensionPermitted = true; this._errorMessage = null; }, prohibitExtension: function (msg) { this._loanExtensionPermitted = false; this._errorMessage = msg; } }; for (var id in bag) { if ((typeof bag[id] === 'string') && !isNaN(bag[id]) && isFinite(bag[id])) { bag[id] = parseFloat(bag[id]); } if (!(id in n)) { n[id] = bag[id]; } } n[-11] = extensionPrice; return n; } }, evaluateExtension: function (bag) { bag[-3] = bag[-3] || bag['loan-amount'] bag[-2] = bag[-2] || bag['loan-term'] bag[-1] = bag[-1] || bag['loan-extension-term'] var values = { discounts_per: {}, discounts_amn: {}, extensions: {}, total_extension_term: 0, prices: {}, feeRates: {}, discounts: {}, discounted: {} } var that = this; var now = new Date().getTime(); var amn = parseFloat(bag[-3]).toFixed(2); var term = parseFloat(bag[-2]).toFixed(0); var extterm = parseFloat(bag[-1]).toFixed(0); if (bag[-7] && (bag[-7] == '-1' || bag[-7] == '1')) { aleg: for (var id in this.pricelists) { if (!('buildPrice' in this.pricelists[id])) { if (!(amn in this.pricelists[id].data)) { var pamn = '0.0'; for (var iamn in this.pricelists[id].data) { if (parseFloat(iamn) > parseFloat(amn)) { if (bag[-7] == '1') { amn = iamn; break aleg; } else { if (parseFloat(pamn) == 0.0) { throw new Error('There is no smaller amount than ' + amn + ' to round down to for pricelist with id ' + id); } amn = pamn; break aleg; } } pamn = iamn; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '1') { amn = pamn; break aleg; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '-1') { amn = pamn; break aleg; } } } } } for (var id in this.pricelists) { if ( id != 4 ) { continue; } if ('buildPrice' in this.pricelists[id]) { var save = bag['pricelist_bag']; bag['pricelist_bag'] = {}; for (var x in save) { bag['pricelist_bag'][x] = save[x]; } for (var x in bag) { if (x != 'pricelist_bag') { bag['pricelist_bag'][x] = bag[x]; } } var pricelist_bag = {}; for (var item in bag['pricelist_bag']) { pricelist_bag[item] = bag['pricelist_bag'][item]; } var pricelistResult = this.pricelists[id].buildPrice(amn, extterm, pricelist_bag); var price = parseFloat(pricelistResult.price); var feeRate = parseFloat(pricelistResult.rate); values.prices[id] = price; values.feeRates[id] = feeRate; } else { if (!this.pricelists[id].data) continue; if (!(amn in this.pricelists[id].data)) { throw new Error('Invalid Amount ' + amn + ' for pricelist with id ' + id); } if (!extterm in this.pricelists[id].data[amn]) { throw new Error('Invalid Term ' + extterm + ' for pricelist with id ' + id + ' for amount ' + amn); } values.prices[id] = parseFloat(this.pricelists[id].data[amn][extterm]); values.feeRates[id] = 0; } } if ('existing-fees' in bag) { for (var id in bag['existing-fees']) { if (bag['existing-fees'][id].amount == 0) { continue; } if (!values.prices[id]) { values.prices[id] = 0; } values.prices[id] += bag['existing-fees'][id].amount; } } this.evaluateExtensionPromotions(now, bag, values); var details2 = { 'percent-discounts' : {}, 'amount-discounts' : {}, 'extensions': {}, original: {}, discount: {}, final: {} }; for (var id in values.prices) { var feeType = null; if (id in this.pricelists) { feeType = this.pricelists[id].type; } else if (id in bag['existing-fees']) { feeType = bag['existing-fees'][id].type; } var discountPercentAr = values.discounts_per[id]; var discountPercent = 0; if (discountPercentAr) { details2['percent-discounts'][feeType] = discountPercentAr; for (var i = 0; i < discountPercentAr.length; i++) { discountPercent += parseFloat(discountPercentAr[i].amount); } } var discountAmountAr = values.discounts_amn[id]; var discountAmount = 0; if (discountAmountAr) { details2['amount-discounts'][feeType] = discountAmountAr; for (var i = 0; i < discountAmountAr.length; i++) { discountAmount += parseFloat(discountAmountAr[i].amount); } } var discount = Math.min(values.prices[id] * discountPercent / 100 + discountAmount, values.prices[id]); var finalAmount = values.prices[id] - discount; values.discounts[id] = parseFloat(discount.toFixed(2)); values.discounted[id] = parseFloat(finalAmount.toFixed(2)); details2.original[feeType] = values.prices[id]; details2.discount[feeType] = values.discounts[id]; details2.final[feeType] = values.discounted[id]; } var ibag = null; var extensionPrice = values.discounted[4]; ibag = this.extensionPermissionRules.freshBag(bag, extensionPrice); this.extensionPermissionRules.evaluate(ibag); var calc_loan_duedate = bag['loan_duedate'] ? new Date(Date.parse(bag['loan_duedate'])) : null; if (calc_loan_duedate) { var calc_loan_is_payday = bag['loan_is_payday']; var calc_extension_permitted = ibag == null || (!ibag._errorMessage && ibag._loanExtensionPermitted); var calc_term = parseInt(extterm); var calc_duedate = null; var calc_now = new Date(); var calc_late = calc_loan_duedate < calc_now; var calc_actDuedate = calc_late ? calc_now : calc_loan_duedate; if (calc_extension_permitted) { calc_duedate = calc_actDuedate; if (calc_loan_is_payday) { calc_duedate.setDate(calc_duedate.getDate() + calc_term); } else { calc_duedate.setMonth(calc_duedate.getMonth() + calc_term); } calc_duedate = (calc_duedate.toISOString()).substr(0, 10); } } return { 'loan-amount': bag[-3], 'loan-term': bag[-2], 'loan-extension-term': bag[-1], 'loan-extension-fees': values.discounted[4], 'loan-extension-duedate': calc_duedate, 'loan-extension-permitted': ibag._loanExtensionPermitted, 'loan-extension-error': ibag._errorMessage, 'loan-original-extension-fees': values.prices[4], 'loan-free-extension': values.total_extension_term, details: details2, }; }, evaluateAdditionalPayout: function (bag) { bag[-3] = bag[-3] || bag['loan-amount'] bag[-2] = bag[-2] || bag['loan-term'] bag[-1] = bag[-1] || bag['loan-additional-payout-amount'] var prices = {} var that = this; var now = new Date().getTime(); var amn = parseFloat(bag[-3]).toFixed(2); var term = parseFloat(bag[-2]).toFixed(0); var additionalPayoutAmount = parseFloat(bag[-1]).toFixed(2); if ('buildPrice' in this.additional_payout_pricelist) { var save = bag['pricelist_bag']; bag['pricelist_bag'] = {}; for (var x in save) { bag['pricelist_bag'][x] = save[x]; } for (var x in bag) { if (x != 'pricelist_bag') { bag['pricelist_bag'][x] = bag[x]; } } prices = this.additional_payout_pricelist.buildPrice(additionalPayoutAmount, term, bag['pricelist_bag']); } else { if (!(additionalPayoutAmount in this.additional_payout_pricelist.data)) { throw new Error('Invalid Amount ' + additionalPayoutAmount + ' for additionalPayoutPricelist with id ' + this.additional_payout_pricelist.id); } if (!term in this.additional_payout_pricelist.data[additionalPayoutAmount]) { throw new Error('Invalid Term ' + term + ' for additionalPayoutPricelist with id ' + this.additional_payout_pricelist.id + ' for amount ' + additionalPayoutAmount); } prices = this.additional_payout_pricelist.data[additionalPayoutAmount][term]; } return { 'loan-amount': bag[-3], 'loan-term': bag[-2], 'loan-additional-payout-amount': bag[-1], 'loan-additional-payout-fees': prices, }; }, calculateAPR: function (startAmount, values) { var PRECISION = 0.00001; var MAX_ATTEMPTS = 1000; var bsMinB = -0.999999999999; var bsMaxB = 2000000000; var principal = startAmount; var attempts = 0; var repaymentTotal = 0; var APRRate = 1; while (Math.abs(repaymentTotal - principal) > PRECISION) { if (attempts >= MAX_ATTEMPTS || (bsMaxB == bsMinB) && (bsMaxB == APRRate)) { return NaN; } attempts++; if (attempts > 1) { if (repaymentTotal < principal) { bsMaxB = APRRate; } else { bsMinB = APRRate; } APRRate = bsMaxB - (bsMaxB - bsMinB) / 2; } repaymentTotal = 0; for (var i = 0; i < values.length; i++) { var rt = Math.pow(1 + APRRate, (i + 1) / 12); // 12 = compounding period repaymentTotal += values[i].payment / rt; } } return APRRate * 100; }, DaysBetween: function(date1, date2) { var oneDay = 24*60*60*1000; return Math.round(Math.abs((date1.getTime() - date2.getTime())/oneDay)); }, XNPV: function(rate, values, daysInYear) { var payment_fee_percentage = 0.00 / 100; var xnpv = 0.0; var firstDate = new Date(values[0].date); for (var i = 0, max = values.length; i < max; i += 1) { var tmp = values[i]; var value; if (tmp.payment < 0) { value = tmp.payment * (1 - payment_fee_percentage); } else { value = tmp.payment * (1 + payment_fee_percentage); } var date = new Date(tmp.date); xnpv += value / Math.pow(1 + rate, this.DaysBetween(firstDate, date)/daysInYear); } return xnpv; }, aprForPayday: function(initialAmount, term, toRepay, daysInYear) { var payment_fee_percentage = 0.00 / 100; return Math.round((Math.pow(toRepay * (1 + payment_fee_percentage) / (initialAmount * (1 - payment_fee_percentage)), daysInYear / term) - 1) * 10000) / 100; }, arForPayday: function (initialAmount, term, toRepay, daysInYear) { var price = toRepay - initialAmount; return Math.round(price / initialAmount * (daysInYear / term) * 10000) / 100; }, rpyForPayday: function (initialAmount, term, toRepay, daysInYear) { var price = toRepay - initialAmount; return Math.round((price / initialAmount / term * daysInYear) * 10000) / 100; }, rpmForPayday: function (initialAmount, term, toRepay, daysInYear) { var price = toRepay - initialAmount; return Math.round((price / initialAmount / term * daysInYear / 12) * 10000) / 100; }, rpdForPayday: function (initialAmount, term, toRepay) { var price = toRepay - initialAmount; return Math.round((price / initialAmount / term) * 10000) / 100; }, XIRR: function(initialAmount, values, guess, forcePayoutDate, daysInYear) { if (!guess) guess = 0.1; var payoutDate = forcePayoutDate ? new Date(forcePayoutDate) : new Date(); payoutDate.setMinutes(0); payoutDate.setHours(0); payoutDate.setSeconds(0); values = values.slice(0); values.unshift({payment:-initialAmount, date:payoutDate}); var x1 = 0.0; var x2 = guess; var f1 = this.XNPV(x1, values, daysInYear); var f2 = this.XNPV(x2, values, daysInYear); for (var i = 0; i < 100; i++) { if ((f1 * f2) < 0.0) break; if (Math.abs(f1) < Math.abs(f2)) { f1 = this.XNPV(x1 += 1.6 * (x1 - x2), values, daysInYear); } else { f2 = this.XNPV(x2 += 1.6 * (x2 - x1), values, daysInYear); } }; if ((f1 * f2) > 0.0) return null; var f = this.XNPV(x1, values, daysInYear); if (f < 0.0) { var rtb = x1; var dx = x2 - x1; } else { var rtb = x2; var dx = x1 - x2; }; for (var i = 0; i < 100; i++) { dx *= 0.5; var x_mid = rtb + dx; var f_mid = this.XNPV(x_mid, values, daysInYear); if (f_mid <= 0.0) rtb = x_mid; if ((Math.abs(f_mid) < 1.0e-6) || (Math.abs(dx) < 1.0e-6)) return Math.max(0, x_mid * 100); }; return null; }, rpyForInstallment: function (interestRate) { return interestRate; }, rpmForInstallment: function (interestRate) { return interestRate / 12; }, rpdForInstallment: function (interestRate, daysInYear) { return interestRate / daysInYear; }, // add base functions fillDiscounts: function (ibag, values) { for (var id in ibag.discounts_per) { if (!(id in values.discounts_per)) { values.discounts_per[id] = []; } for (var i = 0; i < ibag.discounts_per[id].length; i++) { values.discounts_per[id].push(ibag.discounts_per[id][i]); } } for (var id in ibag.discounts_amn) { if (!(id in values.discounts_amn)) { values.discounts_amn[id] = []; } for (var i = 0; i < ibag.discounts_amn[id].length; i++) { values.discounts_amn[id].push(ibag.discounts_amn[id][i]); } } if (!('designations' in values)) { values.designations = {}; } for (var promo_id in ibag.designations) { values.designations[promo_id] = ibag.designations[promo_id]; } for (var promo_id in ibag.customer_data) { if (!('customer_data' in values)) { values.customer_data = {}; } values.customer_data[promo_id] = ibag.customer_data[promo_id]; } var totalTerm = 0; for (var i = 0; i < ibag.extensions.length; i++) { var promo_id = ibag.extensions[i].id; if (!(promo_id in values.extensions)) { values.extensions[promo_id] = 0; } values.extensions[promo_id] += ibag.extensions[i].term; values.total_extension_term += ibag.extensions[i].term; } }, round: function (value, interval, mode) { var returnValue = null; var value = value / interval; switch (mode) { case 0: //FUNCTION_ROUND_FLOOR returnValue = Math.floor(value); break; case 1: //FUNCTION_ROUND_CEIL returnValue = Math.ceil(value); break; case 3: //FUNCTION_ROUND_HALF_DOWN returnValue = -Math.round(-value); break; case 2: //FUNCTION_ROUND_HALF_UP returnValue = Math.round(value); break; } return returnValue ? returnValue / (1 / interval) : returnValue; }, freshBag: function (bag, promo_id) { var that = this; var n = { discounts_per: {}, discounts_amn: {}, extensions: [], designations: {}, customer_data: {}, addInstallmentPromotionPercent: function (feetype, amount, installment_index) { if (!(feetype in this.discounts_per)) { this.discounts_per[feetype] = []; } this.discounts_per[feetype].push({ amount: amount, id: promo_id, installment_index: installment_index }); }, addInstallmentPromotion: function (feetype, amount, installment_index) { if (!(feetype in this.discounts_amn)) { this.discounts_amn[feetype] = []; } this.discounts_amn[feetype].push({ amount: amount, id: promo_id, installment_index: installment_index }); }, addDiscountPercent: function (feetype, amount) { if (!(feetype in this.discounts_per)) { this.discounts_per[feetype] = []; } this.discounts_per[feetype].push({ amount: amount, id: promo_id }); }, addDiscount: function (feetype, amount) { if (!(feetype in this.discounts_amn)) { this.discounts_amn[feetype] = []; } this.discounts_amn[feetype].push({ amount: amount, id: promo_id }); }, setDesignation: function (designation) { this.designations[promo_id] = designation; }, addFreeExtension: function (term) { this.extensions.push({ term: term, id: promo_id }); }, getCustomerData: function (type) { if ('customer-data' in bag && type in bag['customer-data']) { return bag['customer-data'][type]; } else { return null; } }, setCustomerData: function (type, data) { if (!(promo_id in this.customer_data)) { this.customer_data[promo_id] = []; } this.customer_data[promo_id].push({ type: type, data: data }); }, round: that.round, }; for (var id in bag) { if (!(id in n)) { n[id] = bag[id]; } } return n; }, evaluateLoanPromotions: function (now, bag, values) { var ibag = {}; var existingpromo = null; var percentpromo = null; var percentpromos = []; var usedPromotions = []; if (bag['existing-promotions']) { var existingPromos = bag['existing-promotions'].sort(function (a, b) { return b.priority - a.priority; }); ibag = this.freshBag(bag, null); for (var i = 0; i < existingPromos.length; i++) { existingpromo = existingPromos[i]; if (existingpromo['type'] == 'percent') { percentpromo = { 'amount': parseFloat(existingpromo['amount']), 'id': existingpromo['promoId'] }; if (existingpromo['installmentIndex'] !== undefined) { // installment index can be 0 and then it wouldnt go in percentpromo['installment_index'] = existingpromo['installmentIndex'] + 1; // + 1 because for promostaging the first installment is index 1 and not 0 } if (!percentpromos[existingpromo['feeTypeId']]) { percentpromos[existingpromo['feeTypeId']] = []; } percentpromos[existingpromo['feeTypeId']].push(percentpromo); usedPromotions.push(existingpromo['promoId'].toString()); } } ibag['discounts_per'] = percentpromos; this.fillDiscounts(ibag, values); } var quit = false; var use_limit = 0; if (!usedPromotions.includes('251') && (use_limit == 0 || !bag['customer-promotions'] || !bag['customer-promotions']['251'] || !bag['customer-promotions']['251']['times-used'] || bag['customer-promotions']['251']['times-used'] < use_limit ) ) { if (bag['bag_promotion_id']) { if (251 == bag['bag_promotion_id']) { quit = this.addPromotionResult(now, bag, values, 1452058920000, 1767009900000, 251); } } else { quit = this.addPromotionResult(now, bag, values, 1452058920000, 1767009900000, 251); } } if (quit) { return; } }, addPromotionResult: function (now, bag, values, start, end, id) { var ibag = {}; var result = null; if (start < now && now < end) { ibag = this.freshBag(bag, id); result = this.promotions[id].evaluate(ibag); this.fillDiscounts(ibag, values); return result.quit; } return false; }, evaluate: function (bag) { bag[-3] = bag[-3] || bag['loan-amount'] bag[-2] = bag[-2] || bag['loan-term'] var values = { discounts_per: {}, discounts_amn: {}, extensions: {}, total_extension_term: 0, prices: {}, feeRates: {}, discounts: {}, discounted: {}, prices_without_tax: {}, discounted_without_tax: {}, discounts_without_tax: {} } var that = this; var now = new Date().getTime(); var amn = parseFloat(bag[-3]).toFixed(2); var term = parseFloat(bag[-2]).toFixed(0); var extterm = bag[-1] == undefined ? term : parseFloat(bag[-1]).toFixed(0); // apr calculation is by default true, unless apr is set var apr = bag[-13] == undefined ? true : bag[-13]; var excludeFeesFromApr = bag['exclude-fees-from-apr'] == undefined ? [] : bag['exclude-fees-from-apr']; if (bag[-7] && (bag[-7] == '-1' || bag[-7] == '1')) { aleg: for (var id in this.pricelists) { if (!('buildPrice' in this.pricelists[id])) { if (!(amn in this.pricelists[id].data)) { var pamn = '0.0'; for (var iamn in this.pricelists[id].data) { if (parseFloat(iamn) > parseFloat(amn)) { if (bag[-7] == '1') { amn = iamn; break aleg; } else { if (parseFloat(pamn) == 0.0) { throw new Error('There is no smaller amount than ' + amn + ' to round down to for pricelist with id ' + id); } amn = pamn; break aleg; } } pamn = iamn; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '1') { amn = pamn; break aleg; } if (parseFloat(pamn) < parseFloat(amn) && bag[-7] == '-1') { amn = pamn; break aleg; } } } } } for (var id in this.pricelists) { if (bag['ignore-fee'] && bag['ignore-fee'][this.fee_types[id]]) { values.prices[id] = 0; continue; } if ('buildPrice' in this.pricelists[id]) { bag['pricelist_bag'] = bag['pricelist_bag'] || {}; for (var x in bag) { if (x != 'pricelist_bag') { bag['pricelist_bag'][x] = bag[x]; } } var pricelistResult = this.pricelists[id].buildPrice(amn, term, bag['pricelist_bag']); values.prices[id] = pricelistResult.price; values.feeRates[id] = pricelistResult.rate; } else { if (!(amn in this.pricelists[id].data)) { throw new Error('Invalid Amount ' + amn + ' for pricelist with id ' + id); } if (!term in this.pricelists[id].data[amn]) { throw new Error('Invalid Term ' + term + ' for pricelist with id ' + id + ' for amount ' + amn); } values.prices[id] = this.pricelists[id].data[amn][term]; values.feeRates[id] = 0; } if (this.pricelists[id].tax_percentage && this.pricelists[id].tax_percentage > 0) { values.prices_without_tax[id] = (values.prices[id] / (1 + parseFloat(this.pricelists[id].tax_percentage))).toFixed(2); } } this.evaluateLoanPromotions(now, bag, values); var details2 = { 'percent-discounts': {}, 'amount-discounts': {}, extensions: {}, original: {}, discount: {}, final: {}, tax_percentage: {}, without_tax: { original: {}, final: {}, discount: {} } }; var productId = false ? 2 : 1; var recalcVersion = 0; if (bag[-42]) { bag[-42].forEach(function (version) { if (version.product_id == productId) { recalcVersion = version.recalc_version; } }); } if (recalcVersion >= 3.1) { function calculateInterestFee(amount, interestRate, daysInYear, term) { return (amount * interestRate / 100 / daysInYear * term).toFixed(2); } function calculateLoanFee(amount, loanFeeRate, daysInYear, term) { return (parseFloat(loanFeeRate) / 100 / daysInYear * amount * term).toFixed(2); } var amount = bag[-3]; if (!values.feeRates[51]) { values.feeRates[51] = 0; } if (!values.feeRates[2]) { values.feeRates[2] = 0; } var daysPerYear = 366; var interestRate = values.feeRates[51]; var loanFeeRate = values.feeRates[2]; var interest = calculateInterestFee(amount, interestRate, daysPerYear, term); var loanFee = calculateLoanFee(amount, loanFeeRate, daysPerYear, term); values.prices[51] = interest; values.prices[2] = loanFee; values.feeRates['interest-fee-rate'] = interestRate; values.feeRates['loan-fee-rate'] = loanFeeRate; if (0.000 > 0) { values.prices_without_tax[51] = (values.prices[51] / (1 + parseFloat(0.000))).toFixed(2); } if (0.000 > 0) { values.prices_without_tax[2] = (values.prices[2] / (1 + parseFloat(0.000))).toFixed(2); } } for (var id in values.prices) { var discountPercentAr = values.discounts_per[id]; var discountPercent = 0; var name = ''; if (id in this.pricelists) { name = this.pricelists[id].type; } else if (id == 51) { name = 'interest-fee'; } else if (id == 2) { name = 'loan-fee'; } if (discountPercentAr) { if (discountPercentAr) { details2['percent-discounts'][name] = discountPercentAr; } for (var i = 0; i < discountPercentAr.length; i++) { discountPercent += parseFloat(discountPercentAr[i].amount); } } var discountAmountAr = values.discounts_amn[id]; var discountAmount = 0; if (discountAmountAr) { details2['amount-discounts'][name] = discountAmountAr; for (var i = 0; i < discountAmountAr.length; i++) { discountAmount += parseFloat(discountAmountAr[i].amount); } } var discount = Math.min(values.prices[id] * discountPercent / 100 + discountAmount, values.prices[id]); var finalAmount = values.prices[id] - discount; values.discounts[id] = parseFloat(discount.toFixed(2)); values.discounted[id] = parseFloat(finalAmount.toFixed(2)); if (values.prices_without_tax[id]) { if (id in this.pricelists) { values.discounted_without_tax[id] = parseFloat((values.discounted[id] / (1 + parseFloat(this.pricelists[id].tax_percentage))).toFixed(2)); } else if (id == 51) { values.discounted_without_tax[id] = parseFloat((values.discounted[id] / (1 + parseFloat(0.000))).toFixed(2)); } else if (id == 2) { values.discounted_without_tax[id] = parseFloat((values.discounted[id] / (1 + parseFloat(0.000))).toFixed(2)); } else { values.discounted_without_tax[id] = values.discounted[id]; } values.discounts_without_tax[id] = parseFloat((values.prices_without_tax[id] - values.discounted_without_tax[id]).toFixed(2)); } } var loan_total = values.discounted[1] + values.discounted[2]; if (values.discounted[51]) { loan_total += values.discounted[51]; } var loan_total_without_tax = (values.discounted_without_tax[1] || values.discounted[1]) + (values.discounted_without_tax[2] || values.discounted[2]); if (values.discounted_without_tax[51] || values.discounted[51]) { loan_total_without_tax += (values.discounted_without_tax[51] || values.discounted[51]); } for (var id in values.prices) { if (id < 0) { continue; } var name = ''; if (id in this.pricelists) { name = this.pricelists[id].type; } else if (id == 51) { name = 'interest-fee'; } else if (id == 2) { name = 'loan-fee'; } details2.original[name] = values.prices[id]; details2.discount[name] = values.discounts[id]; details2.final[name] = values.discounted[id]; details2.without_tax.original[name] = values.prices_without_tax[id] || values.prices[id]; details2.without_tax.discount[name] = values.discounts_without_tax[id] || values.discounts[id]; details2.without_tax.final[name] = values.discounted_without_tax[id] || values.discounted[id]; if (id in this.pricelists) { details2.tax_percentage[name] = parseFloat(this.pricelists[id].tax_percentage || 0); details2.without_tax.original[name] = values.prices_without_tax[id] || values.prices[id]; details2.without_tax.discount[name] = values.discounts_without_tax[id] || values.discounts[id]; details2.without_tax.final[name] = values.discounted_without_tax[id] || values.discounted[id]; } else { var interest_tax_percantage = parseFloat(0.000); details2.tax_percentage[name] = parseFloat(interest_tax_percantage || 0); details2.without_tax.original[name] = parseFloat(values.prices[id] / (1 + interest_tax_percantage)).toFixed(2); details2.without_tax.discount[name] = parseFloat(values.discounts[id] / (1 + interest_tax_percantage)).toFixed(2); details2.without_tax.final[name] = parseFloat(values.discounted[id] / (1 + interest_tax_percantage)).toFixed(2); } } if ((bag[-15] || false) == false) { delete details2.without_tax; delete details2.tax_percentage; } var ret = { 'loan-amount': bag[-3], 'loan-term': bag[-2], 'loan-repay-amount': values.discounted[1], 'loan-total': loan_total, 'loan-free-extension': values.total_extension_term, 'annual-loan-fee-rate': (values.feeRates[2]/ 100).toFixed(10), details: details2, }; var total_fee_cost_values = 0; if (values.prices['2']) { ret['loan-fees'] = values.discounted[2]; ret['loan-original-fees'] = values.prices[2]; total_fee_cost_values += values.discounted[2]; } if (values.prices['51']) { ret['loan-interest-fees'] = values.discounted['51']; ret['loan-original-interest-fees'] = values.prices['51']; ret['loan-interest-fee-type-id'] = 51; total_fee_cost_values += values.discounted[51]; } ret['loan-total-fee-cost'] = total_fee_cost_values; if (values.customer_data) { ret['customer-data'] = values.customer_data; } if (values.feeRates) { ret['fee-rates'] = values.feeRates; } var loanFee = 2; var interestFee = 51; var preparationFee = null; var principalFee = 1; if ((bag[-15] || false) != false) { ret['without_tax'] = { 'loan-repay-amount': values.discounted_without_tax[principalFee] || values.discounted[principalFee], 'loan-fees': values.discounted_without_tax[loanFee] || values.discounted[loanFee], 'loan-original-fees': values.prices_without_tax[loanFee] || values.prices[loanFee], 'loan-total': loan_total_without_tax, }; } if (apr == true) { //calculate apr for Payday var recalcVersion = 0; if (bag[-42]) { bag[-42].forEach(function (version) { if (version.product_id == 1) { recalcVersion = version.recalc_version; } }); } var daysInYear = recalcVersion >= 3.1 ? 366 : 365; var discounted_params = parseFloat(bag[-3]) + parseFloat(bag['additional-apr-calculation-cost'] || 0) + parseFloat(values.discounted[loanFee] || 0) + parseFloat(values.discounted[interestFee] || 0); if (preparationFee) { discounted_params = discounted_params + parseFloat(values.discounted[preparationFee] || 0); } ret['loan-apr'] = this.aprForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), discounted_params, daysInYear); ret['loan-ar'] = this.arForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), discounted_params, daysInYear); ret['loan-rpy'] = this.rpyForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), discounted_params, daysInYear); ret['loan-rpm'] = this.rpmForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), discounted_params, daysInYear); ret['loan-rpd'] = this.rpdForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), discounted_params); var original_params = parseFloat(bag[-3]) + parseFloat(bag['additional-apr-calculation-cost'] || 0) + parseFloat(values.prices[loanFee] || 0) + parseFloat(values.prices[interestFee] || 0); if (preparationFee) { original_params = original_params + parseFloat(values.prices[preparationFee] || 0); } ret['loan-apr-original'] = this.aprForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), original_params, daysInYear); ret['loan-ar-original'] = this.arForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), original_params, daysInYear); ret['loan-rpy-original'] = this.rpyForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), original_params, daysInYear); ret['loan-rpm-original'] = this.rpmForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), original_params, daysInYear); ret['loan-rpd-original'] = this.rpdForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), original_params); if ((bag[-15] || false) != false) { discounted_params = parseFloat(bag[-3]) + parseFloat(bag['additional-apr-calculation-cost'] || 0) + (!values.discounted_without_tax[loanFee] ? parseFloat(values.discounted[loanFee] || 0) : parseFloat(values.discounted_without_tax[loanFee] || 0)) + (!values.discounted_without_tax[interestFee] ? parseFloat(values.discounted[interestFee] || 0) : parseFloat(values.discounted_without_tax[interestFee] || 0)); if (preparationFee) { discounted_params = discounted_params + (!values.discounted_without_tax[preparationFee] ? parseFloat(values.discounted[preparationFee] || 0) : parseFloat(values.discounted_without_tax[preparationFee] || 0)); } ret['loan-apr'] = this.aprForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), discounted_params, daysInYear); original_params = parseFloat(bag[-3]) + parseFloat(bag['additional-apr-calculation-cost'] || 0) + (!values.prices_without_tax[loanFee] ? parseFloat(values.prices[loanFee] || 0) : parseFloat(values.prices_without_tax[loanFee] || 0)) + (!values.prices_without_tax[interestFee] ? parseFloat(values.prices[interestFee] || 0) : parseFloat(values.prices_without_tax[interestFee] || 0)); if (preparationFee) { original_params = original_params + (!values.prices_without_tax[preparationFee] ? parseFloat(values.prices[preparationFee] || 0) : parseFloat(values.prices_without_tax[preparationFee] || 0)); } ret['loan-apr-original'] = this.aprForPayday(parseFloat(bag[-3]), parseFloat(bag[-2]), original_params, daysInYear); } } let baseDate = bag['calculation-date'] ? new Date(bag['calculation-date']) : new Date(); baseDate.setDate(baseDate.getDate() + bag[-2]); ret['loan-duedate'] = new Date(baseDate); return ret; }, fields: { 190: 'Affiliate', 423: 'Amount', 460: 'Status', 799: 'Loan count', 802: 'Delay', 1071: 'Id', 1217: 'Id', 2438: 'Is First Loan', 2538: 'Verification Mode', 2593: 'Dc Category', 2788: 'Open principal', 2789: 'Original loan fees', 3141: 'Product', 3251: 'Has Open Payday Loan', 3252: 'Has Open Creditline', 3253: 'Has Open Installment Loan', 3256: 'Next installment remaining debt', 3353: 'Installment Delay', 3626: 'Extension Count', 4054: 'Cost loan fees', 4102: 'Late installment remaining debt (w/o LF)', 4190: 'Fee sum without principal', 5266: 'is active early settlement', 5320: 'Repaid installments count', 5875: 'has open LV helper', 6054: 'Last Instantor Succesful Verification', 7560: 'is_force_settled', }, dateValidationDefinition: { evaluate: function (bag) { var control = { canceled: false, quit: false }; (function () { bag["isValid"](); })(); return control; }, freshBag: function (bag, date_to_check) { var n = { date_to_check: date_to_check, holidays: [], valid: false, confirmDate: function (checkDate) { var resultDate = null; if (checkDate === null) { checkDate = "1900-01-01"; } // Check if it is a correct Date object if (checkDate instanceof Date && !isNaN(checkDate.getMonth())) { resultDate = checkDate; } if (typeof checkDate === 'string') { resultDate = new Date(checkDate); // Check if it is a correct date if (isNaN(resultDate.getMonth())) { resultDate = new Date("1900-01-01"); } } if (resultDate === null) { resultDate = new Date("1900-01-01"); } resultDate = new Date(this.getDateToString(resultDate)); resultDate.setMinutes(resultDate.getMinutes() + resultDate.getTimezoneOffset()); return resultDate; }, getDateToString: function (date) { return date.getFullYear() + '-' + ("0" + (date.getMonth() + 1 )).slice(-2) + '-' + ("0" + date.getDate()).slice(-2); }, getValidDateToString: function () { if (!this.valid) { return null; } var date = this.confirmDate(this.date_to_check); return this.getDateToString(date); }, getDay: function () { var date = this.confirmDate(this.date_to_check); return date.getDate(); }, getMonth: function () { var date = this.confirmDate(this.date_to_check); // date.getMonth is 0-indexed return (date.getMonth() + 1); }, getYear: function () { var date = this.confirmDate(this.date_to_check); return date.getFullYear(); }, getDayOfWeek: function () { var date = this.confirmDate(this.date_to_check); return date.getDay(); }, daysInCurrentMonth: function () { var date = this.confirmDate(new Date()); return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(); }, isHoliday: function () { var date = this.confirmDate(this.date_to_check); for(var i = 0; i < this.holidays.length; ++i) { holiday = this.confirmDate(this.holidays[i]); if (Date.parse(date) === Date.parse(holiday)) { return true; } } return false; }, daysFromNow: function () { var now = this.confirmDate(new Date()); var dateToCheck = this.confirmDate(this.date_to_check); var diff = Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()) - Date.UTC(dateToCheck.getFullYear(), dateToCheck.getMonth(), dateToCheck.getDate()); return (Math.floor(diff / (24 * 60 * 60 * 1000)) * -1); }, isValid: function () { this.valid = true; } }; for (var id in bag) { if (!(id in n)) { n[id] = bag[id]; } } return n; }, getRange: function (wished_range) { var max_range = 50; if (wished_range === null || wished_range > max_range || wished_range < 1) { return max_range; } return wished_range; }, getOffset: function (wished_offset) { var min_offset = 0; if (wished_offset === null || wished_offset < min_offset) { return min_offset; } return wished_offset; }, getValidDates: function (bag, offset, range) { range = this.getRange(range); var date = new Date(); date.setDate(date.getDate() + parseInt(this.getOffset(offset))); var validDays = []; for (var i = 0; i < range; i++) { var _date = new Date(date); _date.setDate(_date.getDate() + i); var ibag = this.freshBag(bag, _date); this.evaluate(ibag); if (ibag.valid) { validDays.push(ibag.getValidDateToString()); } } return validDays; }, }, }, }; })(); ;