'use strict'; ((factory) => { if (typeof module !== 'undefined') { const scMathUtil = require('./scMathUtil').getUtil(); const commonConstants = require('./common_constants'); module.exports = factory(scMathUtil, commonConstants); } else { window.calculateUtil = factory(scMathUtil, commonConstants); } })((scMathUtil, commonConstants) => { function standar(exp) { //去空格 exp = exp.replace(/\s/g, ''); //( to ( exp = exp.replace(/(/g, '('); //)to ) exp = exp.replace(/)/g, ')'); //,to , exp = exp.replace(/,/g, ','); //f to F exp = exp.replace(new RegExp('f', 'g'), 'F'); return exp; } /** * 获取累进办法计算的金额 * @param {Number} baseFee - 基准金额 * @param {String} name - 使用累进计算的基数名称(需要与累进库中的名称匹配) * @param {Array} progressiveData - 项目的累进数据(property.progressiveInterval) * @param {Number | String} taxType - 项目的计税方式 * @param {Number} decimal - 精度 * @param {Object} deficiency - 不足处理映射 @example: {'路线工程监理费': 20000 } // 不足2万按2万 * @param {Object} beyond - 超出处理映射 @example: {'路线工程监理费': 500000 } // 超过50万按50万 * @return {Number} */ function getProgressiveFee(baseFee, name, progressiveData, taxType, decimal, deficiency, beyond) { if (!progressiveData) { throw '该项目不存在累进区间数据'; } //根据基数名称匹配累进库数据,标准化以免(())等不同导致不匹配 const matchProgressiveData = progressiveData.find(item => standar(item.name) === standar(name)); if (!matchProgressiveData) { throw `计算基数{${name}}不存在累进区间数据`; } // 将原始数据转换成方便处理的数据:[{feeRate: xx, min: 0, max: 200, minOpr: '(', maxOpr: ']'}] const progression = matchProgressiveData.progression.map(item => { let feeRateField = +taxType === commonConstants.TaxType.NORMAL ? 'generalRate' : +taxType === commonConstants.TaxType.SIMPLE ? 'simpleRate' : ''; if (!feeRateField) { throw `计算基数{${name}}累进区间费率数据错误`; } // item.interval内容: eg (0,200]、[300,500) [1000,+).... const interval = standar(item.interval); // ( => 大于 [ => 大于等于 ) => 小于 ] => 小于等于 const minReg = /([\(\[])(\d+)/; const minMatch = minReg.exec(interval); if (!minMatch || !minMatch[1] || !minMatch[2]) { throw `计算基数{${name}}累进区间数据错误`; } const minOpr = minMatch[1]; // 后台数据单位为万元,这里转为为元 const min = parseFloat(minMatch[2]) * 10000; const maxReg = /[\,,]([\d\+]+)([\)\]])/; const maxMatch = maxReg.exec(interval); if (!maxMatch || !maxMatch[1] || !maxMatch[2]) { throw `计算基数{${name}}累进区间数据错误`; } const max = maxMatch[1] === '+' ? 'infinity' : parseFloat(maxMatch[1]) * 10000; const maxOpr = maxMatch[2]; return { feeRate: item[feeRateField], min, minOpr, max, maxOpr } }); progression.sort((a, b) => a.min - b.min); // 基数所在区间 const withinData = progression.find(item => { const oprMiddle = item.max === 'infinity' ? '+' : ''; const oprLink = item.minOpr + oprMiddle + item.maxOpr; switch (oprLink) { case '()': return baseFee > item.min && baseFee < item.max; case '(]': return baseFee > item.min && baseFee <= item.max; case '[)': return baseFee >= item.min && baseFee < item.max; case '[]': return baseFee >= item.min && baseFee <= item.max; case '(+)': case '(+]': return baseFee > item.min; case '[+)': case '[+]': return baseFee >= item.min; default: return false; } }); if (!withinData) { return 0; } // 累进计算 let fee = 0; //累进之前的区间 for (let i = 0; i < progression.indexOf(withinData); i++) { const perData = progression[i]; fee += (perData.max - perData.min) * perData.feeRate * 0.01; } //累进所在区间 fee = scMathUtil.roundForObj(fee + (baseFee - withinData.min) * withinData.feeRate * 0.01, decimal); // 不足、超出处理 const deficiencyFee = deficiency && deficiency[name] || 0; const beyondFee = beyond && beyond[name] || 0; return deficiencyFee && fee > 0 && fee < deficiencyFee ? deficiencyFee : beyondFee && fee > beyondFee ? beyondFee : fee; } /** * 该基数包含的累进基数 * @param {String} calcBase - 计算基数 * @param {Array} progression - 累进基数名称数组 * @return {Array} */ function getProgressive(calcBase, progression) { if (typeof calcBase !== 'string' || !progression) { return []; } const reg = /{[^}]+}/g; const matched = calcBase.match(reg); if (!matched) { return []; } return matched .filter(mStr => progression.some(pStr => `{${pStr}}` === mStr)) .map(mStr => mStr.replace(/[{}]/g, '')); } /** * 该基数是否含有累进基数 * @param {String} calcBase - 计算基数 * @param {Array} progression - 累进基数名称数组 * @return {Boolean} */ function isProgressive(calcBase, progression) { const progressiveBase = getProgressive(calcBase, progression); return !!progressiveBase.length; } return { getProgressiveFee, isProgressive, getProgressive, }; });