material_exponent_shard.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. 'use strict';
  2. /**
  3. * 期计量 数据模型
  4. *
  5. * @author Mai
  6. * @date 2018/8/13
  7. * @version
  8. */
  9. const auditConst = require('../const/audit').material;
  10. const materialConst = require('../const/material');
  11. const MaterialCalculator = require('../lib/material_calc');
  12. const needUpdateArray = ['weight_num', 'm_price', 'remark'];
  13. module.exports = app => {
  14. class MaterialExponentShard extends app.BaseService {
  15. /**
  16. * 构造函数
  17. *
  18. * @param {Object} ctx - egg全局变量
  19. * @return {void}
  20. */
  21. constructor(ctx) {
  22. super(ctx);
  23. this.tableName = 'material_exponent_shard';
  24. }
  25. /**
  26. * 添加指数清单
  27. * @return {void}
  28. */
  29. async add(transaction, material, id, remark = null) {
  30. const materialStages = material.is_stage_self ? await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: material.id } }) : [];
  31. const materialNodes = material.exponent_node ? await transaction.select(this.ctx.service.materialExponentNode.tableName, { where: { mid: material.id } }) : [];
  32. const insertDatas = [];
  33. const copyInsertData = {
  34. tid: this.ctx.tender.id,
  35. mid: material.id,
  36. me_id: id,
  37. };
  38. if (remark) copyInsertData.remark = remark;
  39. if (materialStages.length > 0) {
  40. for (const ms of materialStages) {
  41. if (materialNodes.length > 0) {
  42. const stageNodes = this._.filter(materialNodes, { ms_id: ms.id });
  43. for (const mn of stageNodes) {
  44. const insertData = this._.cloneDeep(copyInsertData);
  45. insertData.ms_id = ms.id;
  46. insertData.mn_id = mn.id;
  47. insertDatas.push(insertData);
  48. }
  49. } else {
  50. const insertData = this._.cloneDeep(copyInsertData);
  51. insertData.ms_id = ms.id;
  52. insertDatas.push(insertData);
  53. }
  54. }
  55. } else if (materialStages.length === 0 && materialNodes.length > 0) {
  56. for (const mn of materialNodes) {
  57. const insertData = this._.cloneDeep(copyInsertData);
  58. insertData.mn_id = mn.id;
  59. insertDatas.push(insertData);
  60. }
  61. }
  62. if (insertDatas.length > 0) await transaction.insert(this.tableName, insertDatas);
  63. }
  64. // 单个修改工料时同步修改
  65. async update(transaction, data, ms_id = null, mn_id = null, needCalc = false) {
  66. const mesInfo = await transaction.get(this.tableName, { tid: this.ctx.tender.id, ms_id, mn_id, me_id: data.id });
  67. const updateData = {
  68. id: mesInfo.id,
  69. };
  70. for (const nu of needUpdateArray) {
  71. if (data[nu] !== undefined && mesInfo[nu] !== data[nu]) updateData[nu] = data[nu];
  72. }
  73. // 如果只有id,则不更新
  74. if (Object.keys(updateData).length > 1) await transaction.update(this.tableName, updateData);
  75. if (updateData.m_price !== undefined || updateData.weight_num !== undefined || needCalc) {
  76. const mnInfo = mn_id ? await transaction.get(this.ctx.service.materialExponentNode.tableName, { mid: this.ctx.material.id, id: mn_id }) : null;
  77. const msInfo = ms_id && !mn_id ? await transaction.get(this.ctx.service.materialStage.tableName, { mid: this.ctx.material.id, id: ms_id }) : null;
  78. const ex_calc = mnInfo ? JSON.parse(mnInfo.ex_calc) : msInfo ? JSON.parse(msInfo.ex_calc) : materialConst.ex_calc;
  79. await this.calcMaterialExTp(transaction, ex_calc, this.ctx.material.id, ms_id, mn_id);
  80. }
  81. return true;
  82. }
  83. async calcMaterialAllExTpByStage(transaction, mid, extra_ms_id = null, decimal = this.ctx.material.exponent_decimal ? this.ctx.material.exponent_decimal : materialConst.exponent_decimal, rate = this.ctx.material.exponent_rate) {
  84. const msList = await this.ctx.service.materialStage.getAllDataByCondition({ where: { mid } });
  85. const exponentList = await transaction.select(this.ctx.service.materialExponent.tableName, { where: { tid: this.ctx.tender.id, is_summary: materialConst.is_summary.yes } });
  86. const allStageExponentList = await transaction.select(this.tableName, { where: { mid } });
  87. const updateStages = [];
  88. for (const ms of msList) {
  89. if (extra_ms_id && ms.id === extra_ms_id) continue;
  90. const [ex_tp, ex_tax_tp, expr] = await this._calcOneExTp(transaction, JSON.parse(ms.ex_calc), ms.id, null, exponentList, allStageExponentList, decimal, rate);
  91. updateStages.push({
  92. id: ms.id,
  93. ex_tp,
  94. ex_tax_tp,
  95. ex_expr: expr,
  96. });
  97. }
  98. if (updateStages.length > 0) await transaction.updateRows(this.ctx.service.materialStage.tableName, updateStages);
  99. }
  100. async calcMaterialAllExTpByNode(transaction, mid, extra_mn_id = null, needCalcStage = true, decimal = this.ctx.material.exponent_decimal ? this.ctx.material.exponent_decimal : materialConst.exponent_decimal, rate = this.ctx.material.exponent_rate) {
  101. const mnList = await transaction.select(this.ctx.service.materialExponentNode.tableName, { where: { mid } });
  102. const exponentList = await transaction.select(this.ctx.service.materialExponent.tableName, { where: { tid: this.ctx.tender.id, is_summary: materialConst.is_summary.yes } });
  103. const allExponentShardList = await transaction.select(this.tableName, { where: { mid } });
  104. const updateNodes = [];
  105. for (const mn of mnList) {
  106. if (extra_mn_id && mn.id === extra_mn_id) continue;
  107. [mn.ex_tp, mn.ex_tax_tp, mn.expr] = await this._calcOneExTp(transaction, JSON.parse(mn.ex_calc), null, mn.id, exponentList, allExponentShardList, decimal, rate);
  108. updateNodes.push({
  109. id: mn.id,
  110. ex_tp: mn.ex_tp,
  111. ex_tax_tp: mn.ex_tax_tp,
  112. ex_expr: mn.expr,
  113. });
  114. }
  115. if (updateNodes.length > 0) await transaction.updateRows(this.ctx.service.materialExponentNode.tableName, updateNodes);
  116. if (needCalcStage) {
  117. const updateStages = [];
  118. const msList = await this.ctx.service.materialStage.getAllDataByCondition({ where: { mid } });
  119. for (const ms of msList) {
  120. // const extra_ms = extra_mn_id ? this._.find(mnList, { id: extra_mn_id }) : null;
  121. // if (extra_ms && extra_ms.ms_id === ms.id) continue;
  122. let stage_ex_tp = 0;
  123. let stage_ex_tax_tp = 0;
  124. const stageMnList = this._.filter(mnList, { ms_id: ms.id });
  125. for (const mn of stageMnList) {
  126. stage_ex_tp = this.ctx.helper.add(stage_ex_tp, mn.ex_tp ? mn.ex_tp : 0);
  127. stage_ex_tax_tp = this.ctx.helper.add(stage_ex_tax_tp, mn.ex_tax_tp ? mn.ex_tax_tp : 0);
  128. }
  129. updateStages.push({
  130. id: ms.id,
  131. ex_tp: stage_ex_tp,
  132. ex_tax_tp: stage_ex_tax_tp,
  133. });
  134. }
  135. if (updateStages.length > 0) await transaction.updateRows(this.ctx.service.materialStage.tableName, updateStages);
  136. }
  137. }
  138. async _calcOneExTp(transaction, ex_calc, msid = null, mnid = null, exponentList, allStageExponentList, decimal, rate) {
  139. let basic_calc = 0;
  140. // let basic_expr = 0;
  141. if (ex_calc) {
  142. for (const calc of ex_calc) {
  143. if (calc.select) {
  144. if (calc.code === 'zdy' && calc.result) {
  145. basic_calc = this.ctx.helper.add(basic_calc, calc.result);
  146. // basic_expr = calc.value;
  147. } else {
  148. basic_calc = this.ctx.helper.add(basic_calc, calc.value);
  149. // basic_expr = this.ctx.helper.add(basic_expr, calc.value);
  150. }
  151. }
  152. }
  153. }
  154. let expr = basic_calc + '*[';
  155. const condition = {};
  156. if (msid !== null) condition.ms_id = msid;
  157. if (mnid !== null) condition.mn_id = mnid;
  158. const stageExponentList = this._.filter(allStageExponentList, condition);
  159. let sumByChange = 0;
  160. let constant = 0;
  161. for (const ex of exponentList) {
  162. const stageEx = this._.find(stageExponentList, { me_id: ex.id });
  163. if (ex.type === materialConst.ex_type[0].value) {
  164. constant = stageEx.weight_num ? stageEx.weight_num : 0;
  165. expr += constant.toString();
  166. } else if (ex.type === materialConst.ex_type[1].value) {
  167. const calc_num = ex.basic_price > 0 ? this.ctx.helper.mul(stageEx.weight_num, this.ctx.helper.div(stageEx.m_price, ex.basic_price)) : 0;
  168. const change = calc_num ? this.ctx.helper.round(calc_num, decimal.qty) : 0;
  169. expr = expr + (change !== 0 ? '+' + stageEx.weight_num.toString() + '*(' + stageEx.m_price.toString() + '/' + ex.basic_price.toString() + ')' : '');
  170. sumByChange = this.ctx.helper.add(sumByChange, change);
  171. }
  172. }
  173. expr += '-1]';
  174. expr = constant !== 0 ? expr : null;
  175. const ex_tp = constant !== 0 ? this.ctx.helper.round(this.ctx.helper.mul(basic_calc, this.ctx.helper.sub(this.ctx.helper.add(constant, sumByChange), 1)), decimal.tp) : null;
  176. const ex_tax_tp = ex_tp !== null ? this.ctx.helper.round(this.ctx.helper.mul(ex_tp, 1 + rate / 100), decimal.tp) : null;
  177. return [ex_tp, ex_tax_tp, expr];
  178. }
  179. // 更改计算总指数金额并返回值和公式
  180. async calcMaterialExTp(transaction, ex_calc, mid, msid = null, mnid = null, decimal = this.ctx.material.exponent_decimal, rate = this.ctx.material.exponent_rate, needCalcStage = true) {
  181. if (!msid && !mnid) throw '参数有误';
  182. const exponentList = await transaction.select(this.ctx.service.materialExponent.tableName, { where: { tid: this.ctx.tender.id, is_summary: materialConst.is_summary.yes } });
  183. const condition = {};
  184. if (msid !== null) condition.ms_id = msid;
  185. if (mnid !== null) condition.mn_id = mnid;
  186. const exponentShardList = await transaction.select(this.tableName, { where: condition });
  187. const [ex_tp, ex_tax_tp, expr] = await this._calcOneExTp(transaction, ex_calc, msid, mnid, exponentList, exponentShardList, decimal, rate);
  188. if (!mnid) {
  189. await transaction.update(this.ctx.service.materialStage.tableName, {
  190. id: msid,
  191. ex_tp,
  192. ex_tax_tp,
  193. ex_expr: expr,
  194. ex_calc: JSON.stringify(ex_calc),
  195. });
  196. } else {
  197. await transaction.update(this.ctx.service.materialExponentNode.tableName, {
  198. id: mnid,
  199. ex_tp,
  200. ex_tax_tp,
  201. ex_expr: expr,
  202. ex_calc: JSON.stringify(ex_calc),
  203. });
  204. if (needCalcStage && msid) {
  205. await this.ctx.service.materialExponentNode.calcStageExTpByNode(transaction, mid, msid);
  206. }
  207. }
  208. return [ex_tp, ex_tax_tp, expr];
  209. }
  210. /**
  211. * 更新新一期的现行价格指数,并返回指数总金额和公式
  212. * @param transaction
  213. * @param tid
  214. * @param mid
  215. * @returns {Promise<number>}
  216. */
  217. async updateNewMaterial(transaction, mid, msid, ctx, stage_id, ex_calc, decimal, rate) {
  218. const stage_list = await ctx.service.stage.getStageMsgByStageId(stage_id);
  219. const calcBase = await ctx.service.stage.getMaterialCalcBase(stage_list, ctx.tender.info);
  220. const old_ex_calc = ex_calc ? JSON.parse(ex_calc) : null;
  221. const new_ex_calc = this._.cloneDeep(materialConst.ex_calc);
  222. for (const bq of new_ex_calc) {
  223. const calc = this._.find(calcBase, { code: bq.code }) || this._.find(calcBase, { code: 'bqwc' });
  224. const oldcalc = old_ex_calc ? this._.find(old_ex_calc, { code: bq.code }) : null;
  225. bq.value = calc.value;
  226. bq.select = oldcalc ? oldcalc.select : bq.select;
  227. }
  228. await this.calcMaterialExTp(transaction, new_ex_calc, mid, msid, null, decimal, rate);
  229. return new_ex_calc;
  230. }
  231. async makeExponentList(tid, data) {
  232. if (!data.mid || !data.stage_id) {
  233. throw '参数错误';
  234. }
  235. const transaction = await this.db.beginTransaction();
  236. try {
  237. const material = await this.ctx.service.material.getDataById(data.mid);
  238. if (!material) {
  239. throw '调差不存在';
  240. }
  241. if (!material.is_stage_self || material.is_new_exponent) {
  242. throw '独立期指数调差工料已生成或非独立期调差';
  243. }
  244. const materialExponentList = await this.ctx.service.materialExponent.getAllDataByCondition({ where: { tid } });
  245. const materialStageInfo = await this.ctx.service.materialStage.getDataByCondition({ mid: data.mid, sid: data.stage_id });
  246. await transaction.delete(this.tableName, { ms_id: materialStageInfo.id });
  247. await transaction.update(this.ctx.service.materialStage.tableName, {
  248. id: materialStageInfo.id,
  249. ex_tp: null,
  250. ex_tax_tp: null,
  251. ex_expr: null,
  252. ex_calc: null,
  253. });
  254. const newExponentList = [];
  255. for (const me of materialExponentList) {
  256. const newExponent = {
  257. tid,
  258. mid: material.id,
  259. ms_id: materialStageInfo.id,
  260. me_id: me.id,
  261. type: me.type,
  262. weight_num: me.weight_num,
  263. m_price: me.m_price,
  264. remark: me.remark,
  265. };
  266. newExponentList.push(newExponent);
  267. }
  268. if (newExponentList.length > 0) await transaction.insert(this.tableName, newExponentList);
  269. // 计算金额
  270. const ex_calc = await this.updateNewMaterial(transaction, material.id, materialStageInfo.id, this.ctx, materialStageInfo.sid, material.ex_calc, material.exponent_decimal ? JSON.parse(material.exponent_decimal) : materialConst.exponent_decimal, material.exponent_rate);
  271. await transaction.commit();
  272. return true;
  273. } catch (err) {
  274. await transaction.rollback();
  275. throw err;
  276. }
  277. }
  278. async insertMsExponent(transaction, tid, mid, ms, preMaterial = null, decimal, rate) {
  279. // 复制工料表并生成
  280. const meList = await transaction.select(this.ctx.service.materialExponent.tableName, { where: { tid } });
  281. if (meList.length > 0) {
  282. const insertStageExponentData = [];
  283. for (const e of meList) {
  284. const oneStageExponentData = {
  285. tid,
  286. mid,
  287. me_id: e.id,
  288. ms_id: ms.id,
  289. type: e.type,
  290. weight_num: e.weight_num,
  291. m_price: e.m_price,
  292. };
  293. insertStageExponentData.push(oneStageExponentData);
  294. }
  295. await transaction.insert(this.tableName, insertStageExponentData);
  296. const stage_list = await this.ctx.service.stage.getStageMsgByStageId(ms.sid);
  297. const calcBase = await this.ctx.service.stage.getMaterialCalcBase(stage_list, this.ctx.tender.info);
  298. let old_ex_calc = null;
  299. if (preMaterial && preMaterial.ex_calc) {
  300. old_ex_calc = JSON.parse(preMaterial.ex_calc);
  301. } else if (preMaterial && preMaterial.is_stage_self) {
  302. // 判断历史期是否存在相同独立期
  303. const allPreMs = await this.ctx.service.materialStage.getAllDataByCondition({ where: { tid: this.ctx.tender.id, sid: ms.sid }, orders: [['id', 'desc']] });
  304. const preMs = this._.find(allPreMs, m => m.mid !== mid);
  305. if (preMs && preMs.ex_calc) {
  306. old_ex_calc = JSON.parse(preMs.ex_calc);
  307. }
  308. }
  309. const new_ex_calc = this._.cloneDeep(materialConst.ex_calc);
  310. for (const bq of new_ex_calc) {
  311. const calc = this._.find(calcBase, { code: bq.code }) || this._.find(calcBase, { code: 'bqwc' });
  312. const oldcalc = old_ex_calc ? this._.find(old_ex_calc, { code: bq.code }) : null;
  313. bq.value = calc.value;
  314. bq.select = oldcalc ? oldcalc.select : bq.select;
  315. }
  316. await this.calcMaterialExTp(transaction, new_ex_calc, mid, ms.id, null, decimal, rate);
  317. }
  318. }
  319. }
  320. return MaterialExponentShard;
  321. };