revise_price.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. 'use strict';
  2. /**
  3. *
  4. * 单价调整计算:
  5. * 1. 台账修订上报,保存台账修订历史时,使用当前单价调整计算一次
  6. * 2. 台账修订完成:计算台账、应用到未审完成期、应用到所有工程变更
  7. * 3. 新增期:检查是否存在未应用的单价变更
  8. * 4. 期审批完成:所有未应用的单价调整,记录应用到该期(记录revise_price.use_stage/use_stage_order) - 一条sql即可
  9. * 5. 期重现审批:上一次应用的所有单价调整,回到未应用状态(revise_price.use_stage/use_stage_order均回到0) - 一条sql即可
  10. *
  11. * @author Mai
  12. * @date
  13. * @version
  14. */
  15. const Ledger = require('./ledger');
  16. const audit = require('../const/audit');
  17. class revisePriceCalc {
  18. constructor(ctx) {
  19. this.ctx = ctx;
  20. }
  21. set price(price) {
  22. this._price = price;
  23. this.common_price_c = [];
  24. this.rela_price_c = [];
  25. price.forEach(x => {
  26. x.rela_lid = x.rela_lid ? x.rela_lid.split(',') : [];
  27. if (x.rela_cid) {
  28. x.rela_cid = x.rela_cid.split(',');
  29. this.rela_price_c.push(x);
  30. } else {
  31. x.his_rela_cid = [];
  32. this.common_price_c.push(x);
  33. }
  34. });
  35. }
  36. get price() {
  37. return this._price;
  38. }
  39. findChangeBillsPrice(b_code, name, unit, unit_price, cid) {
  40. const helper = this.ctx.helper;
  41. const p = this.rela_price_c.find(x => {
  42. return b_code === x.b_code && name === x.name && unit === x.unit && helper.numEqual(unit_price, x.org_price) && x.rela_cid.indexOf(cid) >= 0;
  43. });
  44. if (p) return p;
  45. return this.common_price_c.find(x => {
  46. return b_code === x.b_code && name === x.name && unit === x.unit && helper.numEqual(unit_price, x.org_price);
  47. });
  48. }
  49. findCommonChangeBillsPrice(b_code, name, unit, unit_price) {
  50. const helper = this.ctx.helper;
  51. const p = this.price.find(x => {
  52. return b_code === x.b_code && name === x.name && unit === x.unit && helper.numEqual(unit_price, x.org_price);
  53. });
  54. return p;
  55. }
  56. _calcContractTpByTp(bills, decimal) {
  57. let activeQty = this.ctx.helper.add(bills.quantity, bills.cur_qc_minus_qty);
  58. let end_contract_qty = bills.cur_contract_qty;
  59. activeQty = this.ctx.helper.add(activeQty, bills.pre_qc_minus_qty);
  60. end_contract_qty = this.ctx.helper.add(end_contract_qty, bills.pre_contract_qty);
  61. const end_contract_tp = this.ctx.helper.mul(this.ctx.helper.div(end_contract_qty, activeQty), bills.total_price, decimal.tp);
  62. return this.ctx.helper.sub(end_contract_tp, bills.pre_contract_tp);
  63. }
  64. /**
  65. * 新增一期计量,检查单价调整
  66. * @param {Object} newStage - 新计量期
  67. * @param {Object} preStage - 上一计量期
  68. * @return { inseretPosData, insertBillsData }
  69. */
  70. async newStagePriceChange(newStage, preStage, transaction) {
  71. const pcTp = { contract_pc_tp: 0, qc_pc_tp: 0, pc_tp: 0, positive_qc_pc_tp: 0, negative_qc_pc_tp: 0 };
  72. // 获取未执行的单价变更,无单价变更不执行
  73. this.price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { tid: newStage.tid, valid: 1, use_stage: 0 } });
  74. if (this.price.length === 0) return pcTp;
  75. // 无截止上期数据不执行
  76. const preBillsData = await this.ctx.service.stageBillsFinal.getAllDataByCondition({ where: { sid: preStage.id } });
  77. if (preBillsData.length === 0) return pcTp;
  78. // 加载树结构
  79. const bills = await this.ctx.service.ledger.getData(newStage.tid);
  80. this.ctx.helper.assignRelaData(bills, [
  81. { data: preBillsData, fields: ['id', 'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'unit_price', 'positive_qc_qty', 'negative_qc_qty', 'positive_qc_tp', 'negative_qc_tp', 'qc_minus_qty'], prefix: 'pre_', relaId: 'lid' },
  82. ]);
  83. const billsTree = new Ledger.billsTree(this.ctx, { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: [] });
  84. billsTree.loadDatas(bills);
  85. // 计算
  86. const result = { ibData: [] };
  87. const helper = this.ctx.helper;
  88. const decimal = this.ctx.tender.info.decimal;
  89. const calcType = this.ctx.tender.info.calc_type;
  90. billsTree.calculateAll(node => {
  91. if (!node.pre_id) return;
  92. if (!node.pre_contract_qty && !node.pre_qc_qty) return;
  93. if (node.children && node.children.length > 0) return;
  94. const priceDiff = helper.sub(node.unit_price, node.pre_unit_price);
  95. if (!priceDiff) return;
  96. node.contract_pc_tp = calcType === 'up'
  97. ? helper.sub(helper.mul(node.pre_contract_qty, node.unit_price, decimal.tp), node.pre_contract_tp)
  98. : 0;
  99. node.qc_pc_tp = helper.sub(helper.mul(node.pre_qc_qty, node.unit_price, decimal.tp), node.pre_qc_tp);
  100. node.pc_tp = helper.add(node.contract_pc_tp, node.qc_pc_tp);
  101. node.positive_qc_pc_tp = helper.sub(helper.mul(node.pre_positive_qc_qty, node.unit_price, decimal.tp), node.pre_positive_qc_tp);
  102. node.negative_qc_pc_tp = helper.sub(helper.mul(node.pre_negative_qc_qty, node.unit_price, decimal.tp), node.pre_negative_qc_tp);
  103. result.ibData.push({
  104. tid: newStage.tid, sid: newStage.id, sorder: newStage.order, lid: node.id, org_price: node.pre_unit_price, unit_price: node.unit_price,
  105. contract_pc_tp: node.contract_pc_tp, qc_pc_tp: node.qc_pc_tp, pc_tp: node.pc_tp,
  106. positive_qc_pc_tp: node.positive_qc_pc_tp, negative_qc_pc_tp: node.negative_qc_pc_tp,
  107. });
  108. });
  109. if (result.ibData.length > 0) await transaction.insert(this.ctx.service.stageBillsPc.tableName, result.ibData);
  110. for (const ibc of result.ibData) {
  111. pcTp.contract_pc_tp = helper.add(pcTp.contract_pc_tp, ibc.contract_pc_tp);
  112. pcTp.qc_pc_tp = helper.add(pcTp.qc_pc_tp, ibc.qc_pc_tp);
  113. pcTp.pc_tp = helper.add(pcTp.pc_tp, ibc.pc_tp);
  114. pcTp.positive_qc_pc_tp = helper.add(pcTp.positive_qc_pc_tp, ibc.positive_qc_pc_tp);
  115. pcTp.negative_qc_pc_tp = helper.add(pcTp.negative_qc_pc_tp, ibc.negative_qc_pc_tp);
  116. }
  117. await transaction.update(this.ctx.service.stage.tableName,
  118. { id: newStage.id, ...pcTp, check_calc: true, cache_time_l: new Date() });
  119. return pcTp;
  120. }
  121. /**
  122. * 期,重新审批,检查单价调整
  123. * @param {Object} stage - 期
  124. * @param {Number} auditOrder - 重新审批,最新审批人序号
  125. * @param {Object} transaction - 事务
  126. */
  127. async stageCheckAgainPriceChange(stage, auditOrder, transaction) {
  128. const pcTp = { contract_pc_tp: 0, qc_pc_tp: 0, pc_tp: 0, positive_qc_pc_tp: 0, negative_qc_pc_tp: 0 };
  129. // 获取未执行的单价变更,无单价变更不执行
  130. this.price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { tid: stage.tid, valid: 1, use_stage: 0 } });
  131. if (this.price.length === 0) return pcTp;
  132. const curBillsData = await this.ctx.service.stageBills.getLastestStageData2(stage.tid, stage.id);
  133. const preBillsData = await this.ctx.service.stageBillsFinal.getAllDataByCondition({ where: { tid: stage.tid, sorder: stage.order - 1 } });
  134. // 加载树结构
  135. const bills = await this.ctx.service.ledger.getData(stage.tid);
  136. this.ctx.helper.assignRelaData(bills, [
  137. { data: curBillsData, fields: ['id', 'contract_qty', 'qc_qty', 'positive_qc_qty', 'negative_qc_qty', 'postil', 'times', 'order', 'ex_stage_qty1', 'qc_minus_qty'], prefix: 'cur_', relaId: 'lid' },
  138. { data: preBillsData, fields: ['id', 'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'unit_price', 'positive_qc_qty', 'negative_qc_qty', 'positive_qc_tp', 'negative_qc_tp', 'qc_minus_qty'], prefix: 'pre_', relaId: 'lid' },
  139. ]);
  140. const billsTree = new Ledger.billsTree(this.ctx, { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: [] });
  141. billsTree.loadDatas(bills);
  142. const stageChange = await this.ctx.service.stageChange.getFinalStageData(stage.tid, stage.id);
  143. // 计算 insertBills billsPriceChange stageChange
  144. const result = { ibData: [], bpcData: [], scData: [] };
  145. const helper = this.ctx.helper;
  146. const decimal = this.ctx.tender.info.decimal;
  147. const said = this.ctx.session.sessionUser.accountId;
  148. const calcType = this.ctx.tender.info.calc_type;
  149. const self = this;
  150. billsTree.calculateAll(node => {
  151. if (node.children && node.children.length > 0) return;
  152. // const priceDiff = helper.sub(node.unit_price, node.pre_unit_price);
  153. // if (!priceDiff) return;
  154. if (node.cur_id && (node.cur_contract_qty || node.cur_qc_qty || node.cur_ex_stage_qty1)) {
  155. const cur_contract_tp = calcType === 'up'
  156. ? helper.mul(node.cur_contract_qty, node.unit_price, decimal.tp)
  157. : self._calcContractTpByTp(node, decimal);
  158. const cur_qc_tp = helper.mul(node.cur_qc_qty, node.unit_price, decimal.tp);
  159. const cur_positive_qc_tp = helper.mul(node.cur_positive_qc_qty, node.unit_price, decimal.tp);
  160. const cur_negative_qc_tp = helper.mul(node.cur_negative_qc_qty, node.unit_price, decimal.tp);
  161. const cur_ex_stage_tp1 = helper.mul(node.cur_ex_stage_qty1, node.unit_price, decimal.tp);
  162. if (cur_contract_tp !== node.cur_contract_tp || cur_qc_tp !== node.cur_qc_tp || cur_positive_qc_tp !== node.cur_positive_qc_tp || cur_negative_qc_tp !== node.cur_positive_qc_tp || cur_ex_stage_tp1 !== node.cur_ex_stage_tp1) {
  163. result.ibData.push({
  164. tid: stage.tid, sid: stage.id, said,
  165. lid: node.id,
  166. times: stage.times, order: auditOrder,
  167. contract_qty: node.cur_contract_qty, contract_tp: cur_contract_tp,
  168. qc_qty: node.cur_qc_qty, qc_tp: cur_qc_tp,
  169. positive_qc_qty: node.cur_positive_qc_qty, positive_qc_tp: cur_positive_qc_tp,
  170. negative_qc_qty: node.cur_negative_qc_qty, negative_qc_tp: cur_negative_qc_tp,
  171. ex_stage_qty1: node.cur_ex_stage_qty1, ex_stage_tp1: cur_ex_stage_tp1,
  172. postil: node.postil,
  173. });
  174. }
  175. }
  176. if (node.pre_id && (node.pre_contract_qty || node.pre_qc_qty)) {
  177. const contract_pc_tp = calcType === 'up' ? helper.sub(helper.mul(node.pre_contract_qty, node.unit_price, decimal.tp), node.pre_contract_tp) : 0;
  178. const qc_pc_tp = helper.sub(helper.mul(node.pre_qc_qty, node.unit_price, decimal.tp), node.pre_qc_tp);
  179. const pc_tp = helper.add(contract_pc_tp, qc_pc_tp);
  180. const positive_qc_pc_tp = helper.sub(helper.mul(node.pre_positive_qc_qty, node.unit_price, decimal.tp), node.pre_positive_qc_tp);
  181. const negative_qc_pc_tp = helper.sub(helper.mul(node.pre_negative_qc_qty, node.unit_price, decimal.tp), node.pre_negative_qc_tp);
  182. if (contract_pc_tp || qc_pc_tp || pc_tp || positive_qc_pc_tp || negative_qc_pc_tp) {
  183. result.bpcData.push({
  184. tid: stage.tid, sid: stage.id, sorder: stage.order, lid: node.id, org_price: node.pre_unit_price, unit_price: node.unit_price,
  185. contract_pc_tp, qc_pc_tp, pc_tp, positive_qc_pc_tp, negative_qc_pc_tp,
  186. });
  187. }
  188. }
  189. const scDetail = stageChange.filter(x => { return x.lid === node.id; });
  190. for (const scd of scDetail) {
  191. result.scData.push({ id: scd.id, unit_price: node.unit_price });
  192. }
  193. });
  194. if (result.ibData.length > 0) await transaction.insert(this.ctx.service.stageBills.tableName, result.ibData);
  195. await transaction.delete(this.ctx.service.stageBillsPc.tableName, { sid: stage.id });
  196. if (result.bpcData.length > 0) await transaction.insert(this.ctx.service.stageBillsPc.tableName, result.bpcData);
  197. if (result.scData.length > 0) await transaction.updateRows(this.ctx.service.stageChange.tableName, result.scData);
  198. for (const bpc of result.bpcData) {
  199. pcTp.contract_pc_tp = helper.add(pcTp.contract_pc_tp, bpc.contract_pc_tp);
  200. pcTp.qc_pc_tp = helper.add(pcTp.qc_pc_tp, bpc.qc_pc_tp);
  201. pcTp.pc_tp = helper.add(pcTp.pc_tp, bpc.pc_tp);
  202. pcTp.positive_qc_pc_tp = helper.add(pcTp.positive_qc_pc_tp, bpc.positive_qc_pc_tp);
  203. pcTp.negative_qc_pc_tp = helper.add(pcTp.negative_qc_pc_tp, bpc.negative_qc_pc_tp);
  204. }
  205. await transaction.update(this.ctx.service.stage.tableName,
  206. { id: stage.id, ...pcTp, check_calc: true, cache_time_l: new Date() });
  207. return pcTp;
  208. }
  209. /**
  210. * 重算工程变更(调整单价)
  211. * @param {Object} change - 工程变更
  212. * @param {Object} transaction - 事务 (无则非事务提交)
  213. */
  214. async calcChange(change, transaction) {
  215. const decimal = this.ctx.tender.info.decimal;
  216. const changeBills = await this.ctx.service.changeAuditList.getAllDataByCondition({ where: { cid: change.cid } });
  217. const updateBills = [];
  218. const sumBills = [];
  219. for (const b of changeBills) {
  220. const p = this.findChangeBillsPrice(b.code, b.name, b.unit, b.unit_price, change.cid);
  221. const settleGcl = b.gcl_id ? this.settleBills.find(x => { return x.lid === b.gcl_id; }) : null;
  222. const settlePos = b.mx_id ? this.settlePos.find(x => { return x.pid === b.mx_id; }): null;
  223. let bills_tp;
  224. if (p && !settleGcl && !settlePos) {
  225. bills_tp = this.ctx.helper.mul(p.new_price, b.spamount, change.tp_decimal || decimal.tp);
  226. updateBills.push({ id: b.id, unit_price: p.new_price, checked_price: bills_tp });
  227. if (!p.rela_cid) p.his_rela_cid.push(change.cid);
  228. } else {
  229. bills_tp = this.ctx.helper.mul(b.unit_price, b.spamount, change.tp_decimal || decimal.tp);
  230. }
  231. let sb;
  232. if (b.gcl_id) {
  233. sb = sumBills.find(x => { return x.gcl_id === b.gcl_id });
  234. if (!sb) {
  235. sb = {gcl_id: b.gcl_id, unit_price: p ? p.new_price : b.unit_price, v_qty: 0, uv_qty: 0, p_qty: 0, n_qty: 0 };
  236. sumBills.push(sb);
  237. }
  238. } else {
  239. sb = { gcl_id: b.gcl_id, unit_price: p ? p.new_price : b.unit_price, v_qty: 0, uv_qty: 0, p_qty: 0, n_qty: 0 };
  240. sumBills.push(sb);
  241. }
  242. if (b.spamount >= 0) {
  243. sb.p_qty = this.ctx.helper.add(sb.p_qty, b.spamount);
  244. } else {
  245. sb.n_qty = this.ctx.helper.add(sb.n_qty, b.spamount);
  246. }
  247. if (b.is_valuation) {
  248. sb.v_qty = this.ctx.helper.add(sb.v_qty, b.spamount);
  249. } else {
  250. sb.uv_qty = this.ctx.helper.add(sb.uv_qty, b.spamount);
  251. }
  252. }
  253. let total_price = 0, positive_tp = 0, negative_tp = 0, valuation_tp = 0, unvaluation_tp = 0;
  254. for (const sb of sumBills) {
  255. sb.qty = this.ctx.helper.add(sb.v_qty, sb.uv_qty);
  256. sb.tp = this.ctx.helper.mul(sb.qty, sb.unit_price, change.tp_decimal || decimal.tp);
  257. sb.v_tp = this.ctx.helper.mul(sb.v_qty, sb.unit_price, change.tp_decimal || decimal.tp);
  258. sb.uv_tp = this.ctx.helper.mul(sb.uv_qty, sb.unit_price, change.tp_decimal || decimal.tp);
  259. sb.p_tp = this.ctx.helper.mul(sb.p_qty, sb.unit_price, change.tp_decimal || decimal.tp);
  260. sb.n_tp = this.ctx.helper.mul(sb.n_qty, sb.unit_price, change.tp_decimal || decimal.tp);
  261. total_price = this.ctx.helper.add(sb.tp, total_price);
  262. valuation_tp = this.ctx.helper.add(sb.v_tp, valuation_tp);
  263. unvaluation_tp = this.ctx.helper.add(sb.uv_tp, unvaluation_tp);
  264. positive_tp = this.ctx.helper.add(sb.p_tp, positive_tp);
  265. negative_tp = this.ctx.helper.add(sb.n_tp, negative_tp);
  266. }
  267. // const total_price = this.ctx.helper.add(valuation_tp, unvaluation_tp);
  268. if (updateBills.length > 0) {
  269. await transaction.updateRows(this.ctx.service.changeAuditList.tableName, updateBills);
  270. await transaction.update(this.ctx.service.change.tableName, { total_price, positive_tp, negative_tp, valuation_tp, unvaluation_tp }, { where: { cid: change.cid } });
  271. }
  272. }
  273. /**
  274. * 重算标段下所有工程变更(调整单价)
  275. * @param {Number} tid - 标段id
  276. * @param {Object} transaction - 事务 (无则非事务提交)
  277. */
  278. async calcAllChanges(tid, transaction) {
  279. const change = await this.ctx.service.change.getAllDataByCondition({ where: { tid, valid: 1 } });
  280. if (change.length === 0) return;
  281. for (const c of change) {
  282. await this.calcChange(c, transaction);
  283. }
  284. const revisePriceUpdate = [];
  285. for (const p of this.common_price_c) {
  286. if (p.his_rela_cid.length > 0) revisePriceUpdate.push({id: p.id, his_rela_cid: p.his_rela_cid.join(',')});
  287. }
  288. if (revisePriceUpdate.length > 0) await transaction.updateRows(this.ctx.service.revisePrice.tableName, revisePriceUpdate);
  289. }
  290. /**
  291. * 重算变更方案(调整单价)
  292. * @param {Object} change - 工程变更
  293. * @param {Object} transaction - 事务 (无则非事务提交)
  294. */
  295. async calcChangePlan(changePlan, transaction) {
  296. const decimal = changePlan.decimal ? JSON.parse(changePlan.decimal) : this.ctx.tender.info.decimal;
  297. const changeBills = await this.ctx.service.changePlanList.getAllDataByCondition({ where: { cpid: changePlan.id } });
  298. const updateBills = [];
  299. let total_price = 0;
  300. for (const b of changeBills) {
  301. const p = this.findCommonChangeBillsPrice(b.code, b.name, b.unit, b.unit_price);
  302. let bills_tp;
  303. if (p) {
  304. bills_tp = this.ctx.helper.mul(p.new_price, b.spamount, decimal.tp);
  305. updateBills.push({ id: b.id, unit_price: p.new_price });
  306. } else {
  307. bills_tp = this.ctx.helper.mul(b.unit_price, b.spamount, decimal.tp);
  308. }
  309. total_price = this.ctx.helper.add(total_price, bills_tp);
  310. }
  311. if (updateBills.length > 0) {
  312. await transaction.updateRows(this.ctx.service.changePlanList.tableName, updateBills);
  313. await transaction.update(this.ctx.service.changePlan.tableName, { id: changePlan.id, total_price});
  314. }
  315. }
  316. async calcAllChangePlan(tid, transaction) {
  317. const changePlan = await this.ctx.service.changePlan.getAllDataByCondition({ where: { tid } });
  318. if (changePlan.length === 0) return;
  319. for (const c of changePlan) {
  320. await this.calcChangePlan(c, transaction);
  321. }
  322. }
  323. /**
  324. * 重算变更申请(调整单价)
  325. * @param {Object} change - 工程变更
  326. * @param {Object} transaction - 事务 (无则非事务提交)
  327. */
  328. async calcChangeApply(changeApply, transaction) {
  329. const decimal = changeApply.decimal ? JSON.parse(changeApply.decimal) : this.ctx.tender.info.decimal;
  330. const changeBills = await this.ctx.service.changeApplyList.getAllDataByCondition({ where: { caid: changeApply.id } });
  331. const updateBills = [];
  332. let total_price = 0;
  333. for (const b of changeBills) {
  334. const p = this.findCommonChangeBillsPrice(b.code, b.name, b.unit, b.unit_price);
  335. let bills_tp;
  336. if (p) {
  337. bills_tp = this.ctx.helper.mul(p.new_price, b.camount, decimal.tp);
  338. updateBills.push({ id: b.id, unit_price: p.new_price });
  339. } else {
  340. bills_tp = this.ctx.helper.mul(b.unit_price, b.camount, decimal.tp);
  341. }
  342. total_price = this.ctx.helper.add(total_price, bills_tp);
  343. }
  344. if (updateBills.length > 0) {
  345. await transaction.updateRows(this.ctx.service.changeApplyList.tableName, updateBills);
  346. await transaction.update(this.ctx.service.changeApply.tableName, { id: changeApply.id, total_price});
  347. }
  348. }
  349. async calcAllChangeApply(tid, transaction) {
  350. const changeApply = await this.ctx.service.changeApply.getAllDataByCondition({ where: { tid } });
  351. if (changeApply.length === 0) return;
  352. for (const c of changeApply) {
  353. await this.calcChangeApply(c, transaction);
  354. }
  355. }
  356. async _calcStage(stage, bills, transaction) {
  357. const pcTp = { contract_pc_tp: 0, qc_pc_tp: 0, pc_tp: 0, positive_qc_pc_tp: 0, negative_qc_pc_tp: 0 };
  358. // 无单价变更不执行
  359. if (this.price.length === 0) return pcTp;
  360. const curBillsData = await this.ctx.service.stageBills.getLastestStageData2(stage.tid, stage.id);
  361. const preBillsData = await this.ctx.service.stageBillsFinal.getAllDataByCondition({ where: { tid: stage.tid, sorder: stage.order - 1 } });
  362. // 加载树结构
  363. this.ctx.helper.assignRelaData(bills, [
  364. { data: curBillsData, fields: ['id', 'contract_qty', 'qc_qty', 'positive_qc_qty', 'negative_qc_qty', 'times', 'order', 'postil', 'ex_stage_qty1', 'ex_stage_tp1', 'qc_minus_qty'], prefix: 'cur_', relaId: 'lid' },
  365. { data: preBillsData, fields: ['id', 'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'unit_price', 'positive_qc_qty', 'negative_qc_qty', 'positive_qc_tp', 'negative_qc_tp', 'qc_minus_qty'], prefix: 'pre_', relaId: 'lid' },
  366. ], 'id', true);
  367. const billsTree = new Ledger.billsTree(this.ctx, { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: [] });
  368. billsTree.loadDatas(bills);
  369. const stageChange = await this.ctx.service.stageChange.getFinalStageData(stage.tid, stage.id);
  370. // 计算 insertBills/updateBills billsPriceChange StageChange
  371. const result = { ibData: [], ubData: [], bpcData: [], scData: [] };
  372. const helper = this.ctx.helper;
  373. const decimal = this.ctx.tender.info.decimal;
  374. const said = this.ctx.session.sessionUser.accountId;
  375. const calcType = this.ctx.tender.info.calc_type;
  376. const self = this;
  377. billsTree.calculateAll(node => {
  378. if (node.children && node.children.length > 0) return;
  379. if (node.cur_id && (node.cur_contract_qty || node.cur_qc_qty || node.cur_ex_stage_qty1)) {
  380. const cur_contract_tp = calcType === 'up'
  381. ? helper.mul(node.cur_contract_qty, node.unit_price, decimal.tp)
  382. : self._calcContractTpByTp(node, decimal);
  383. const cur_qc_tp = helper.mul(node.cur_qc_qty, node.unit_price, decimal.tp);
  384. const cur_positive_qc_tp = helper.mul(node.cur_positive_qc_qty, node.unit_price, decimal.tp);
  385. const cur_negative_qc_tp = helper.mul(node.cur_negative_qc_qty, node.unit_price, decimal.tp);
  386. const cur_ex_stage_tp1 = helper.mul(node.cur_ex_stage_qty1, node.unit_price, decimal.tp);
  387. if (cur_contract_tp !== node.cur_contract_tp || cur_qc_tp !== node.cur_qc_tp || cur_positive_qc_tp !== node.cur_positive_qc_tp || cur_negative_qc_tp !== node.cur_positive_qc_tp || cur_ex_stage_tp1 !== node.cur_ex_stage_tp1) {
  388. if (node.cur_times === stage.times && node.cur_order === 0) {
  389. result.ubData.push({
  390. id: node.cur_id,
  391. contract_tp: cur_contract_tp, qc_tp: cur_qc_tp,
  392. positive_qc_tp: cur_positive_qc_tp, negative_qc_tp: cur_negative_qc_tp,
  393. ex_stage_tp1: cur_ex_stage_tp1,
  394. });
  395. } else {
  396. result.ibData.push({
  397. tid: stage.tid, sid: stage.id, said,
  398. lid: node.id, times: stage.times, order: 0,
  399. contract_qty: node.cur_contract_qty, contract_tp: cur_contract_tp,
  400. qc_qty: node.cur_qc_qty, qc_tp: cur_qc_tp,
  401. positive_qc_qty: node.cur_positive_qc_qty, positive_qc_tp: cur_positive_qc_tp,
  402. negative_qc_qty: node.cur_negative_qc_qty, negative_qc_tp: cur_negative_qc_tp,
  403. ex_stage_qty1: node.cur_ex_stage_qty1, ex_stage_tp1: cur_ex_stage_tp1,
  404. postil: node.cur_postil,
  405. });
  406. }
  407. }
  408. }
  409. const scDetail = stageChange.filter(x => { return x.lid === node.id; });
  410. for (const scd of scDetail) {
  411. result.scData.push({ id: scd.id, unit_price: node.unit_price });
  412. }
  413. const priceDiff = helper.sub(node.unit_price, node.pre_unit_price);
  414. if (!priceDiff) return;
  415. if (node.pre_id && (node.pre_contract_qty || node.pre_qc_qty)) {
  416. node.contract_pc_tp = calcType === 'up' ? helper.sub(helper.mul(node.pre_contract_qty, node.unit_price, decimal.tp), node.pre_contract_tp) : 0;
  417. node.qc_pc_tp = helper.sub(helper.mul(node.pre_qc_qty, node.unit_price, decimal.tp), node.pre_qc_tp);
  418. node.pc_tp = helper.add(node.contract_pc_tp, node.qc_pc_tp);
  419. node.positive_qc_pc_tp = helper.sub(helper.mul(node.pre_positive_qc_qty, node.unit_price, decimal.tp), node.pre_positive_qc_tp);
  420. node.negative_qc_pc_tp = helper.sub(helper.mul(node.pre_negative_qc_qty, node.unit_price, decimal.tp), node.pre_negative_qc_tp);
  421. result.bpcData.push({
  422. tid: stage.tid, sid: stage.id, sorder: stage.order, lid: node.id, org_price: node.pre_unit_price, unit_price: node.unit_price,
  423. contract_pc_tp: node.contract_pc_tp, qc_pc_tp: node.qc_pc_tp, pc_tp: node.pc_tp,
  424. positive_qc_pc_tp: node.positive_qc_pc_tp, negative_qc_pc_tp: node.negative_qc_pc_tp,
  425. });
  426. }
  427. });
  428. if (result.ibData.length > 0) await transaction.insert(this.ctx.service.stageBills.tableName, result.ibData);
  429. if (result.ubData.length > 0) await transaction.updateRows(this.ctx.service.stageBills.tableName, result.ubData);
  430. await transaction.delete(this.ctx.service.stageBillsPc.tableName, { sid: stage.id });
  431. if (result.bpcData.length > 0) await transaction.insert(this.ctx.service.stageBillsPc.tableName, result.bpcData);
  432. if (result.scData.length > 0) await transaction.updateRows(this.ctx.service.stageChange.tableName, result.scData);
  433. for (const bpc of result.bpcData) {
  434. pcTp.contract_pc_tp = helper.add(pcTp.contract_pc_tp, bpc.contract_pc_tp);
  435. pcTp.qc_pc_tp = helper.add(pcTp.qc_pc_tp, bpc.qc_pc_tp);
  436. pcTp.pc_tp = helper.add(pcTp.pc_tp, bpc.pc_tp);
  437. pcTp.positive_qc_pc_tp = helper.add(pcTp.positive_qc_pc_tp, bpc.positive_qc_pc_tp);
  438. pcTp.negative_qc_pc_tp = helper.add(pcTp.negative_qc_pc_tp, bpc.negative_qc_pc_tp);
  439. }
  440. await transaction.update(this.ctx.service.stage.tableName,
  441. { id: stage.id, ...pcTp, check_calc: true, cache_time_l: new Date() });
  442. return pcTp;
  443. }
  444. async _calcStageWithoutPc(stage, bills, transaction) {
  445. // 无单价变更不执行
  446. if (this.price.length === 0) return;
  447. const curBillsData = await this.ctx.service.stageBills.getLastestStageData2(stage.tid, stage.id);
  448. // 加载树结构
  449. this.ctx.helper.assignRelaData(bills, [
  450. { data: curBillsData, fields: ['id', 'contract_qty', 'qc_qty', 'positive_qc_qty', 'negative_qc_qty', 'times', 'order', 'postil', 'qc_minus_qty'], prefix: 'cur_', relaId: 'lid' },
  451. ], 'id', true);
  452. const billsTree = new Ledger.billsTree(this.ctx, { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: [] });
  453. billsTree.loadDatas(bills);
  454. const stageChange = await this.ctx.service.stageChange.getFinalStageData(stage.tid, stage.id);
  455. // 计算 insertBills/updateBills StageChange
  456. const result = { ibData: [], ubData: [], scData: [] };
  457. const helper = this.ctx.helper;
  458. const decimal = this.ctx.tender.info.decimal;
  459. const said = this.ctx.session.sessionUser.accountId;
  460. const calcType = this.ctx.tender.info.calc_type;
  461. const self = this;
  462. billsTree.calculateAll(node => {
  463. if (node.children && node.children.length > 0) return;
  464. if (node.cur_id && (node.cur_contract_qty || node.cur_qc_qty)) {
  465. const cur_contract_tp = calcType === 'up'
  466. ? helper.mul(node.cur_contract_qty, node.unit_price, decimal.tp)
  467. : self._calcContractTpByTp(node, decimal);
  468. const cur_qc_tp = helper.mul(node.cur_qc_qty, node.unit_price, decimal.tp);
  469. const cur_positive_qc_tp = helper.mul(node.cur_positive_qc_qty, node.unit_price, decimal.tp);
  470. const cur_negative_qc_tp = helper.mul(node.cur_negative_qc_qty, node.unit_price, decimal.tp);
  471. if (cur_contract_tp !== node.cur_contract_tp || cur_qc_tp !== node.cur_qc_tp || cur_positive_qc_tp !== node.cur_positive_qc_tp || cur_negative_qc_tp !== node.cur_positive_qc_tp) {
  472. if (node.cur_times === stage.times && node.cur_order === 0) {
  473. result.ubData.push({
  474. id: node.cur_id,
  475. contract_tp: cur_contract_tp, qc_tp: cur_qc_tp,
  476. positive_qc_tp: cur_positive_qc_tp, negative_qc_tp: cur_negative_qc_tp,
  477. });
  478. } else {
  479. result.ibData.push({
  480. tid: stage.tid, sid: stage.id, said,
  481. lid: node.id, times: stage.times, order: 0,
  482. contract_qty: node.cur_contract_qty, contract_tp: cur_contract_tp,
  483. qc_qty: node.cur_qc_qty, qc_tp: cur_qc_tp,
  484. positive_qc_qty: node.cur_positive_qc_qty, positive_qc_tp: cur_positive_qc_tp,
  485. negative_qc_qty: node.cur_negative_qc_qty, negative_qc_tp: cur_negative_qc_tp,
  486. postil: node.cur_postil,
  487. });
  488. }
  489. }
  490. }
  491. const scDetail = stageChange.filter(x => { return x.lid === node.id; });
  492. for (const scd of scDetail) {
  493. result.scData.push({ id: scd.id, unit_price: node.unit_price });
  494. }
  495. });
  496. if (result.ibData.length > 0) await transaction.insert(this.ctx.service.stageBills.tableName, result.ibData);
  497. if (result.ubData.length > 0) await transaction.updateRows(this.ctx.service.stageBills.tableName, result.ubData);
  498. if (result.scData.length > 0) await transaction.updateRows(this.ctx.service.stageChange.tableName, result.scData);
  499. if (result.ibData.length > 0 || result.ubData.length > 0) await transaction.update(this.ctx.service.stage.tableName, { id: stage.id, check_calc: true});
  500. }
  501. /**
  502. * 计算修订台账
  503. * @param {Object}revise - 最新一次台账修订(此处不检查)
  504. * @param {Object} transaction - 事务 (无则非事务提交)
  505. */
  506. async calcReviseLedger(revise, transaction) {
  507. const xmj = await this.ctx.helper.loadLedgerDataFromOss(revise.curHis.bills_file);
  508. xmj.forEach(x => {
  509. delete x.is_tp;
  510. delete x.gxby_status;
  511. delete x.gxby_limit;
  512. delete x.gxby_ratio;
  513. delete x.gxby_url;
  514. delete x.dagl_status;
  515. delete x.dagl_limit;
  516. delete x.dagl_ratio;
  517. delete x.dagl_url;
  518. });
  519. const pos = await this.ctx.helper.loadLedgerDataFromOss(revise.curHis.pos_file);
  520. pos.forEach(p => {
  521. p.in_time = new Date(p.in_time);
  522. delete p.gxby_status;
  523. delete p.gxby_limit;
  524. delete p.gxby_ratio;
  525. delete p.gxby_url;
  526. delete p.dagl_status;
  527. delete p.dagl_limit;
  528. delete p.dagl_ratio;
  529. delete p.dagl_url;
  530. });
  531. await transaction.delete(this.ctx.service.ledger.tableName, { tender_id: revise.tid });
  532. if (xmj.length > 0) await transaction.insert(this.ctx.service.ledger.tableName, xmj);
  533. await transaction.delete(this.ctx.service.pos.tableName, { tid: revise.tid });
  534. if (pos.length > 0) await transaction.insert(this.ctx.service.pos.tableName, pos);
  535. // 应用到未审完成期
  536. const stages = await this.ctx.service.stage.getAllDataByCondition({ where: { tid: revise.tid }, orders: [['order', 'asc']] });
  537. const latestStage = stages[stages.length - 1];
  538. let pcTp;
  539. if (latestStage && latestStage.status !== audit.stage.status.checked) {
  540. for (const s of stages) {
  541. if (s.status === audit.stage.status.checked) continue;
  542. if (!pcTp) {
  543. pcTp = await this._calcStage(s, xmj, transaction);
  544. } else {
  545. await this._calcStageWithoutPc(s, xmj, transaction);
  546. }
  547. }
  548. }
  549. return pcTp;
  550. }
  551. async calcRevise(revise, transaction) {
  552. if (revise.tid !== this.ctx.tender.id) throw '数据错误';
  553. this.price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { rid: revise.id } });
  554. this.settleStatus = this.ctx.service.settle.settleStatus;
  555. this.settleBills = revise.readySettle ? await this.ctx.service.settleBills.getAllDataByCondition({ where: { settle_id: revise.readySettle.id, settle_status: this.settleStatus.finish } }) : [];
  556. this.settlePos = revise.readySettle ? await this.ctx.service.settlePos.getAllDataByCondition({ where: { settle_id: revise.readySettle.id }}) : [];
  557. const pcTp = await this.calcReviseLedger(revise, transaction);
  558. // 引用到所有工程变更
  559. await this.calcAllChanges(revise.tid, transaction);
  560. await this.calcAllChangePlan(revise.tid, transaction);
  561. await this.calcAllChangeApply(revise.tid, transaction);
  562. return pcTp;
  563. }
  564. }
  565. module.exports = revisePriceCalc;