calculate_util.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. 'use strict';
  2. ((factory) => {
  3. if (typeof module !== 'undefined') {
  4. const scMathUtil = require('./scMathUtil').getUtil();
  5. const commonConstants = require('./common_constants');
  6. module.exports = factory(scMathUtil, commonConstants);
  7. } else {
  8. window.calculateUtil = factory(scMathUtil, commonConstants);
  9. }
  10. })((scMathUtil, commonConstants) => {
  11. function standar(exp) {
  12. //去空格
  13. exp = exp.replace(/\s/g, '');
  14. //( to (
  15. exp = exp.replace(/(/g, '(');
  16. //)to )
  17. exp = exp.replace(/)/g, ')');
  18. //,to ,
  19. exp = exp.replace(/,/g, ',');
  20. //f to F
  21. exp = exp.replace(new RegExp('f', 'g'), 'F');
  22. return exp;
  23. }
  24. /**
  25. * 获取累进办法计算的金额
  26. * @param {Number} baseFee - 基准金额
  27. * @param {String} name - 使用累进计算的基数名称(需要与累进库中的名称匹配)
  28. * @param {Array} progressiveData - 项目的累进数据(property.progressiveInterval)
  29. * @param {Number | String} taxType - 项目的计税方式
  30. * @param {Number} decimal - 精度
  31. * @param {Object} deficiency - 不足处理映射 @example: {'路线工程监理费': 20000 } // 不足2万按2万
  32. * @param {Object} beyond - 超出处理映射 @example: {'路线工程监理费': 500000 } // 超过50万按50万
  33. * @return {Number}
  34. */
  35. function getProgressiveFee(baseFee, name, progressiveData, taxType, decimal, deficiency, beyond) {
  36. if (!progressiveData) {
  37. throw '该项目不存在累进区间数据';
  38. }
  39. //根据基数名称匹配累进库数据,标准化以免(())等不同导致不匹配
  40. const matchProgressiveData = progressiveData.find(item => standar(item.name) === standar(name));
  41. if (!matchProgressiveData) {
  42. throw `计算基数{${name}}不存在累进区间数据`;
  43. }
  44. // 将原始数据转换成方便处理的数据:[{feeRate: xx, min: 0, max: 200, minOpr: '(', maxOpr: ']'}]
  45. const progression = matchProgressiveData.progression.map(item => {
  46. let feeRateField = +taxType === commonConstants.TaxType.NORMAL
  47. ? 'generalRate'
  48. : +taxType === commonConstants.TaxType.SIMPLE
  49. ? 'simpleRate'
  50. : '';
  51. if (!feeRateField) {
  52. throw `计算基数{${name}}累进区间费率数据错误`;
  53. }
  54. // item.interval内容: eg (0,200]、[300,500) [1000,+)....
  55. const interval = standar(item.interval);
  56. // ( => 大于 [ => 大于等于 ) => 小于 ] => 小于等于
  57. const minReg = /([\(\[])(\d+)/;
  58. const minMatch = minReg.exec(interval);
  59. if (!minMatch || !minMatch[1] || !minMatch[2]) {
  60. throw `计算基数{${name}}累进区间数据错误`;
  61. }
  62. const minOpr = minMatch[1];
  63. // 后台数据单位为万元,这里转为为元
  64. const min = parseFloat(minMatch[2]) * 10000;
  65. const maxReg = /[\,,]([\d\+]+)([\)\]])/;
  66. const maxMatch = maxReg.exec(interval);
  67. if (!maxMatch || !maxMatch[1] || !maxMatch[2]) {
  68. throw `计算基数{${name}}累进区间数据错误`;
  69. }
  70. const max = maxMatch[1] === '+' ? 'infinity' : parseFloat(maxMatch[1]) * 10000;
  71. const maxOpr = maxMatch[2];
  72. return {
  73. feeRate: item[feeRateField],
  74. min,
  75. minOpr,
  76. max,
  77. maxOpr
  78. }
  79. });
  80. progression.sort((a, b) => a.min - b.min);
  81. // 基数所在区间
  82. const withinData = progression.find(item => {
  83. const oprMiddle = item.max === 'infinity' ? '+' : '';
  84. const oprLink = item.minOpr + oprMiddle + item.maxOpr;
  85. switch (oprLink) {
  86. case '()':
  87. return baseFee > item.min && baseFee < item.max;
  88. case '(]':
  89. return baseFee > item.min && baseFee <= item.max;
  90. case '[)':
  91. return baseFee >= item.min && baseFee < item.max;
  92. case '[]':
  93. return baseFee >= item.min && baseFee <= item.max;
  94. case '(+)':
  95. case '(+]':
  96. return baseFee > item.min;
  97. case '[+)':
  98. case '[+]':
  99. return baseFee >= item.min;
  100. default:
  101. return false;
  102. }
  103. });
  104. if (!withinData) {
  105. return 0;
  106. }
  107. // 累进计算
  108. let fee = 0;
  109. //累进之前的区间
  110. for (let i = 0; i < progression.indexOf(withinData); i++) {
  111. const perData = progression[i];
  112. fee += (perData.max - perData.min) * perData.feeRate * 0.01;
  113. }
  114. //累进所在区间
  115. fee = scMathUtil.roundForObj(fee + (baseFee - withinData.min) * withinData.feeRate * 0.01, decimal);
  116. // 不足、超出处理
  117. const deficiencyFee = deficiency && deficiency[name] || 0;
  118. const beyondFee = beyond && beyond[name] || 0;
  119. return deficiencyFee && fee > 0 && fee < deficiencyFee
  120. ? deficiencyFee
  121. : beyondFee && fee > beyondFee
  122. ? beyondFee
  123. : fee;
  124. }
  125. /**
  126. * 该基数包含的累进基数
  127. * @param {String} calcBase - 计算基数
  128. * @param {Array} progression - 累进基数名称数组
  129. * @return {Array}
  130. */
  131. function getProgressive(calcBase, progression) {
  132. if (typeof calcBase !== 'string' || !progression) {
  133. return [];
  134. }
  135. const reg = /{[^}]+}/g;
  136. const matched = calcBase.match(reg);
  137. if (!matched) {
  138. return [];
  139. }
  140. return matched
  141. .filter(mStr => progression.some(pStr => `{${pStr}}` === mStr))
  142. .map(mStr => mStr.replace(/[{}]/g, ''));
  143. }
  144. /**
  145. * 该基数是否含有累进基数
  146. * @param {String} calcBase - 计算基数
  147. * @param {Array} progression - 累进基数名称数组
  148. * @return {Boolean}
  149. */
  150. function isProgressive(calcBase, progression) {
  151. const progressiveBase = getProgressive(calcBase, progression);
  152. return !!progressiveBase.length;
  153. }
  154. return {
  155. getProgressiveFee,
  156. isProgressive,
  157. getProgressive,
  158. };
  159. });