/* eslint-disable */
import { Injector } from './injector';
/**
* Creates a tax charges injector
* @class
*/
class InjectorTaxCharges extends Injector {
/**
* @param {struct} skv_config Struct passed in when initializing the injector
* @param {array} arr_tax_years Array of basic tax years that we will manipulate
* and pass back
* @param {array} arr_tax_charges Array of tax charges data from pluto
* @param {array} arr_tax_company_vehicle Array of company vehicle tax data from pluto
*/
constructor(
skv_config = {},
arr_tax_years = [],
arr_tax_charges = [],
arr_tax_company_vehicle = [],
) {
super();
this.skv_config = skv_config;
this.arr_tax_years = arr_tax_years;
this.arr_tax_charges = arr_tax_charges;
this.arr_tax_company_vehicle = arr_tax_company_vehicle;
// expose functions
this.removeUnrequiredRegions = InjectorTaxCharges.removeUnrequiredRegions;
this.removeChargeYears = InjectorTaxCharges.removeChargeYears;
this.duplicateChargeYears = InjectorTaxCharges.duplicateChargeYears;
this.addTaxChargesToTaxYears = InjectorTaxCharges.addTaxChargesToTaxYears;
// remove unrequired regions
this.arr_tax_charges = InjectorTaxCharges.removeUnrequiredRegions(this.skv_config.region_code, this.arr_tax_charges);
// if the first year of tax charges doesn't match up with the first year
// of tax years we need to remove it (and potentially others).
// This may happen in the case where a start date of April 20xx is passed in)
if (this.arr_tax_years[0].year_slash !== this.arr_tax_charges[0].year) {
this.arr_tax_charges = InjectorTaxCharges.removeChargeYears(this.arr_tax_years, this.arr_tax_charges);
}
// check whether we need to add extra years to tax charges
if (this.arr_tax_years.length > this.arr_tax_charges.length) {
this.arr_tax_charges = InjectorTaxCharges.duplicateChargeYears(this.arr_tax_years, this.arr_tax_charges);
} else if(this.arr_tax_years.length < this.arr_tax_charges.length) {
this.arr_tax_charges = InjectorTaxCharges.removeChargeYears(this.arr_tax_years, this.arr_tax_charges);
}
// update the limits and thresholds to be based on months occupied
this.arr_tax_charges = this.updateToUseMonthsOccupied(this.arr_tax_years, this.arr_tax_charges);
// check whether we need to add extra years to tax company vehicle
if (
this.arr_tax_company_vehicle.length > 0
&& this.arr_tax_years.length > this.arr_tax_company_vehicle.length
) {
this.arr_tax_company_vehicle = InjectorTaxCharges.duplicateChargeYears(this.arr_tax_years, this.arr_tax_company_vehicle);
}
this.arr_tax_years = InjectorTaxCharges.addTaxChargesToTaxYears(this.arr_tax_years, this.arr_tax_charges);
const cnt_years = this.arr_tax_years.length;
// merge tax company vehicle in to tax years if we have it
if (this.arr_tax_company_vehicle.length > 0) {
for (let i = 0; i < cnt_years; i += 1) {
this.arr_tax_years[i].skv_tax_company_vehicle = this.arr_tax_company_vehicle[i];
}
}
}
/**
* We don't want redundant region data in tax charges, so remove it
* @param {string} region_code_to_keep
* @returns {array} Tax charges with regions removed from income tax
*/
static removeUnrequiredRegions(region_code_to_keep, arr_tax_charges) {
const cnt_years = arr_tax_charges.length;
// loop through each tax charge year
for (let i = 0; i < cnt_years; i += 1) {
// currently only income tax has different regions
const arr_income_tax = arr_tax_charges[i].income_tax;
// remove any structs that aren't equal to the array
arr_income_tax.regions = arr_income_tax.regions.filter((region) => region.name === region_code_to_keep);
if (arr_income_tax.regions.length === 0) {
throw new Error(`A region code of ${region_code_to_keep} was not found in income tax regions of provided tax charges`);
}
// eslint-disable-next-line no-param-reassign
arr_tax_charges[i].income_tax = arr_income_tax;
}
return arr_tax_charges;
}
/**
* See if we need to duplicate tax charge years to match the tax years
* @param {array} arr_tax_years Basic tax years
* @param {array} arr_tax_rates Tax rates, bands etc could be charges or company vehicle from pluto
* @returns {array} Amended tax charges array
*/
static duplicateChargeYears(arr_tax_years, arr_tax_rates) {
const cnt_tax_years = arr_tax_years.length;
const cnt_tax_rates = arr_tax_rates.length;
// start with the original array and add any years we don't have to it
const arr_return = JSON.parse(JSON.stringify(arr_tax_rates));
if (cnt_tax_years > cnt_tax_rates) {
// how many years we need to add on to the end of the tax charges array
const num_to_duplicate = cnt_tax_years - cnt_tax_rates;
// get the last year we have data for
const skv_duplicate = JSON.parse(JSON.stringify(arr_return[cnt_tax_rates - 1]));
for (let i = 0; i < num_to_duplicate; i += 1) {
// delete skv_duplicate.year;
const skv_new_rate_struct = JSON.parse(JSON.stringify(skv_duplicate));
// add 1 to the year
const arr_year = skv_new_rate_struct.year.split('/');
arr_year[0] = Number(arr_year[0]) + (i + 1);
arr_year[1] = Number(arr_year[1]) + (i + 1);
skv_new_rate_struct.year = `${arr_year[0]}/${arr_year[1]}`;
arr_return.push(skv_new_rate_struct);
}
}
return arr_return;
}
/**
* See if we need to remove tax charge years to match the tax years
* @param {array} arr_tax_years Basic tax years
* @param {array} arr_tax_rates Tax rates, bands etc could be charges or company vehicle from pluto
* @returns {array} Amended tax charges array
*/
static removeChargeYears(arr_tax_years, arr_tax_rates) {
const cnt_tax_years = arr_tax_years.length;
const cnt_tax_rates = arr_tax_rates.length;
// start with the original array and add any years we don't have to it
let arr_return = JSON.parse(JSON.stringify(arr_tax_rates));
// remove any extra charge years
if (cnt_tax_years < cnt_tax_rates) {
const num_to_remove = cnt_tax_rates - cnt_tax_years;
const end_idx = (cnt_tax_rates) - num_to_remove;
arr_return = arr_return.slice(0, end_idx);
}
let allow_removal = true;
// remove any non-matching charge years, starting with the first in the
// array
for(let i = 0; i < cnt_tax_years; i++) {
// if we have found a matching year already then don't allow any
// subsequent removals
if (
arr_return.length > i
&& arr_tax_years[i].year_slash === arr_return[i].year
) {
allow_removal = false;
}
// if no mismatched tax charges have been removed then check to do
// so here
if (
allow_removal
&& arr_return.length > i
&& arr_tax_years[i].year_slash !== arr_return[i].year
) {
// remove first element of tax charges
arr_return.shift();
}
}
// if no tax charges left throw warning
if (arr_return.length === 0) {
throw new Error('No matching tax charges for tax years');
}
return arr_return;
}
/**
* Updated tax years with the tax charges
* @param {array} arr_tax_years
* @param {array} arr_tax_charges
* @returns {array}
*/
static addTaxChargesToTaxYears(arr_tax_years, arr_tax_charges) {
const arr_return = JSON.parse(JSON.stringify(arr_tax_years));
const cnt_years = arr_return.length;
// merge tax charges in to tax years
for (let i = 0; i < cnt_years; i += 1) {
arr_return[i].skv_tax_charges = arr_tax_charges[i];
// check tax charge year matches tax year year and throw error if it doesn't
if (arr_return[i].year_slash !== arr_tax_charges[i].year) {
throw new Error(`Tax year ${arr_return[i].year_slash} does not match tax charge ${arr_tax_charges[i].year}`);
}
}
return arr_return;
}
/**
* Description
* @param {data_type} param_name Description
* @returns {data_type} Description
*/
updateToUseMonthsOccupied(arr_tax_years, arr_tax_rates) {
// at this point tax years and tax rates length will match
const cnt_tax_rates = arr_tax_rates.length;
const arr_return = [];
for (let i = 0; i < cnt_tax_rates; i += 1) {
const skv_yr_tax_rates = JSON.parse(JSON.stringify(arr_tax_rates[i]));
const skv_tax_year = arr_tax_years[i];
const { months_occupied } = skv_tax_year;
const coverage_ratio = months_occupied / 12;
const skv_updated_rates = this.formatData(skv_yr_tax_rates, coverage_ratio);
arr_return.push(skv_updated_rates);
}
return arr_return;
}
/**
* Recurse through a deeply nested object and update the desired key values
* with the coverage ratio
* @param {anything} data
* @param {number} coverage_ratio
* @param {string} curr_key We need current key to check whether its a value
* to multiply by coverage ratio
* @returns {anything}
*/
formatData(data, coverage_ratio, curr_key = '') {
// if one of these keys is found then apply the coverage ratio
const arr_keys_to_update = ['limit', 'restriction_threshold'];
if (typeof data === 'object') {
const arr_keys = Object.keys(data);
const cnt_keys = arr_keys.length;
const data_return = JSON.parse(JSON.stringify(data));
for (let i = 0; i < cnt_keys; i += 1) {
const data_key = arr_keys[i];
data_return[data_key] = this.formatData(data_return[data_key], coverage_ratio, data_key);
}
return data_return;
} if (
typeof data === 'number'
// check whether its one of the designated keys to update
&& arr_keys_to_update.includes(curr_key)
) {
// we'll just have a value at this point
return data * coverage_ratio;
}
return data;
}
}
export {
InjectorTaxCharges,
};