rptCustomData.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. 'use strict';
  2. /**
  3. * 定制报表 注意不做任何混用,也不做任何继承
  4. *
  5. * @author Mai
  6. * @date
  7. * @version
  8. */
  9. const auditConst = require('../const/audit');
  10. const Ledger = require('./ledger');
  11. /**
  12. * 季华项目 定制报表
  13. * 汇总表,流水汇总2个标段(N个),汇总到期,每期汇总3个人的数据(3个),工程量清单流水表,并根据截至本期变更令使用情况筛选
  14. *
  15. * 借用 通用汇总标段选的界面
  16. * 故配置可与汇总标段选择相同
  17. *
  18. * define: {
  19. * "title": "请选择汇总的标段", "type": "month/final/checked-final/stage",
  20. * "defaultCompare": [1, 2, 3], // 结果按序 rn_qty, rn_tp
  21. * "match": { "quality": [2, 3], "qty": "<0" }, // class根据变更类型过滤,qty根据数量过滤
  22. * "merge": true,
  23. * }
  24. * defaultCompare为默认选择的审批人,0为原报,1-N为1-N审
  25. * match为保留的类型
  26. * 如需要用户选择审批人,则应配置selectCompare(目前不可用,不可配置,如需使用,则需要额外界面),为后期可能的变动预留
  27. *
  28. */
  29. class jhHelper {
  30. constructor (ctx) {
  31. this.ctx = ctx;
  32. this.result = [];
  33. }
  34. async _getValidStages(tenderId) {
  35. const stages = await this.ctx.service.stage.db.select(this.ctx.service.stage.tableName, {
  36. where: { tid: tenderId },
  37. orders: [['order', 'desc']],
  38. });
  39. if (stages.length !== 0) {
  40. const lastStage = stages[0];
  41. if (lastStage.status === auditConst.stage.status.uncheck && lastStage.user_id !== this.ctx.session.sessionUser.accountId) {
  42. stages.splice(0, 1);
  43. }
  44. }
  45. return stages;
  46. }
  47. async _getCheckedStages(tenderId) {
  48. const stages = await this.db.select(this.ctx.service.stage.tableName, {
  49. where: { tid: tenderId },
  50. orders: [['order', 'desc']],
  51. });
  52. if (stages.length !== 0) {
  53. const lastStage = stages[0];
  54. if (lastStage.status !== auditConst.stage.status.checked) {
  55. stages.splice(0, 1);
  56. }
  57. }
  58. return stages;
  59. }
  60. /**
  61. * 查询本期所有变更明细
  62. * @param tid
  63. * @param sid
  64. * @returns {Promise<void>}
  65. */
  66. async getCurChangeDetailData(tid, sid) {
  67. const sql = 'SELECT sc.*, c.type As c_type, c.class As c_class, c.quality As c_quality FROM ' + this.ctx.service.stageChange.tableName + ' sc' +
  68. ' Left Join ' + this.ctx.service.change.tableName + ' c ON sc.cid = c.cid' +
  69. ' WHERE sc.tid = ? and sc.sid = ?';
  70. return await this.ctx.service.stageChange.db.query(sql, [tid, sid]);
  71. }
  72. async getPreChangeDetailData(tid, sOrder) {
  73. const sql = 'SELECT sc.*, c.type As c_type, c.class As c_class, c.quality As c_quality FROM ' + this.ctx.service.stageChangeFinal.tableName + ' sc' +
  74. ' Left Join ' + this.ctx.service.change.tableName + ' c ON sc.cid = c.cid' +
  75. ' Left Join ' + this.ctx.service.stage.tableName + ' s ON sc.sid = s.id' +
  76. ' WHERE sc.tid = ? and s.order < ?';
  77. return await this.ctx.service.stageChangeFinal.db.query(sql, [tid, sOrder]);
  78. }
  79. getLastestAuditors(auditors) {
  80. const index = {};
  81. for (const auditor of auditors) {
  82. if (!index[auditor.aid] || auditor.order > index[auditor.aid].order) index[auditor.aid] = auditor;
  83. }
  84. const result = [];
  85. for (const i in index) {
  86. result.push(index[i]);
  87. }
  88. result.sort((x, y) => { return x.order - y.order; });
  89. return result;
  90. }
  91. _loadChangeDetail(billsIndex, changeDetail, gsDefine, prefix) {
  92. for (const cd of changeDetail) {
  93. if (!cd.qty) continue;
  94. let match = false;
  95. for (const m of gsDefine.match) {
  96. if (m.quality === cd.c_quality && ((m.minus && cd.qty < 0) || (!m.minus && cd.qty > 0))) match = true;
  97. }
  98. if (!match) continue;
  99. const bills = billsIndex[cd.lid];
  100. if (!bills) continue;
  101. if (!bills[prefix + 'cd']) bills[prefix + 'cd'] = [];
  102. bills[prefix + 'cd'].push(cd);
  103. if (cd.pid) {
  104. const pos = bills.pos.find(x => {return x.id === cd.pid});
  105. if (pos) {
  106. if (!pos[prefix + 'cd']) pos[prefix + 'cd'] = [];
  107. pos[prefix + 'cd'].push(cd);
  108. }
  109. }
  110. }
  111. }
  112. _loadMergeResult(bills, prefixes, decimal) {
  113. const rst = {
  114. id: bills.id,
  115. tid: bills.tender_id,
  116. b_code: bills.b_code,
  117. name: bills.name,
  118. unit: bills.unit,
  119. unit_price: bills.unit_price
  120. };
  121. if (bills.pos && bills.pos.length > 0) {
  122. for (const p of bills.pos) {
  123. let gather = false;
  124. if (p.pre_cd && p.pre_cd.length > 0) gather = true;
  125. for (const prefix of prefixes) {
  126. if (p[prefix + 'cd'] && p[prefix + 'cd'].length > 0) gather = true;
  127. }
  128. if (gather) {
  129. rst.qc_qty = this.ctx.helper.add(rst.qc_qty, p.qc_qty);
  130. rst.pre_qc_qty = this.ctx.helper.add(rst.pre_qc_qty, p.pre_qc_qty);
  131. rst.end_qc_qty = this.ctx.helper.add(rst.end_qc_qty, p.end_qc_qty);
  132. for (const prefix of prefixes) {
  133. rst[prefix + 'qc_qty'] = this.ctx.helper.add(rst[prefix + 'qc_qty'], p[prefix + 'qc_qty']);
  134. }
  135. }
  136. }
  137. rst.qc_tp = this.ctx.helper.mul(rst.unit_price, rst.qc_qty, decimal.tp);
  138. rst.pre_qc_tp = this.ctx.helper.mul(rst.unit_price, rst.pre_qc_qty, decimal.tp);
  139. rst.end_qc_tp = this.ctx.helper.add(rst.pre_qc_tp, rst.qc_tp);
  140. for (const prefix of prefixes) {
  141. rst[prefix + 'qc_tp'] = this.ctx.helper.mul(rst.unit_price, rst[prefix + 'qc_qty'], decimal.tp);
  142. }
  143. } else {
  144. rst.qc_qty = bills.qc_qty;
  145. rst.qc_tp = bills.qc_tp;
  146. rst.pre_qc_qty = bills.pre_qc_qty;
  147. rst.pre_qc_tp = bills.pre_qc_tp;
  148. rst.end_qc_qty = bills.end_qc_qty;
  149. rst.end_qc_tp = bills.end_qc_tp;
  150. for (const prefix of prefixes) {
  151. rst[prefix + 'qc_qty'] = bills[prefix + 'qc_qty'];
  152. rst[prefix + 'qc_tp'] = bills[prefix + 'qc_tp'];
  153. }
  154. }
  155. this.result.push(rst);
  156. }
  157. _loadResult(bills, prefixes, decimal) {
  158. if (bills.pos) {
  159. for (const p of bills.pos) {
  160. let load = false;
  161. if (p.pre_cd && p.pre_cd.length > 0) load = true;
  162. for (const prefix of prefixes) {
  163. if (p[prefix + 'cd'] && p[prefix + 'cd'].length > 0) load = true;
  164. }
  165. if (!load) continue;
  166. const rst = {
  167. b_code: bills.b_code,
  168. name: bills.name,
  169. unit: bills.unit,
  170. unit_price: bills.unit_price,
  171. };
  172. rst.qc_qty = p.qc_qty;
  173. rst.qc_tp = this.ctx.helper.mul(bills.unit_price, p.qc_qty, decimal.tp);
  174. rst.pre_qc_qty = p.pre_qc_qty;
  175. rst.pre_qc_tp = this.ctx.helper.mul(bills.unit_price, p.pre_qc_qty, decimal.tp);
  176. rst.end_qc_qty = p.end_qc_qty;
  177. rst.end_qc_tp = this.ctx.helper.add(rst.qc_tp, p.pre_qc_tp);
  178. for (const prefix of prefixes) {
  179. rst[prefix + 'qc_qty'] = p[prefix + 'qc_qty'];
  180. rst[prefix + 'qc_tp'] = this.ctx.helper.mul(bills.unit_price, p[prefix + 'qc_qty'], decimal.tp);
  181. }
  182. this.result.push(rst);
  183. }
  184. } else {
  185. const rst = {
  186. b_code: bills.b_code,
  187. name: bills.name,
  188. unit: bills.unit,
  189. unit_price: bills.unit_price,
  190. };
  191. rst.qc_qty = bills.qc_qty;
  192. rst.qc_tp = bills.qc_tp;
  193. rst.pre_qc_qty = bills.pre_qc_qty;
  194. rst.pre_qc_tp = bills.pre_qc_tp;
  195. rst.end_qc_qty = bills.end_qc_qty;
  196. rst.end_qc_tp = bills.end_qc_tp;
  197. for (const prefix of prefixes) {
  198. rst[prefix + 'qc_qty'] = bills[prefix + 'qc_qty'];
  199. rst[prefix + 'qc_tp'] = bills[prefix + 'qc_tp'];
  200. }
  201. this.result.push(rst);
  202. }
  203. }
  204. _generateResult(billsData, gsDefine, decimal) {
  205. for (const bills of billsData) {
  206. let load = false;
  207. if (bills.pre_cd && bills.pre_cd.length > 0) load = true;
  208. for (const dc of gsDefine.defaultCompare) {
  209. if (bills['r' + dc + '_cd'] && bills['r' + dc + '_cd'].length > 0) load = true;
  210. }
  211. if (!load) continue;
  212. gsDefine.merge ? this._loadMergeResult(bills, this.prefixes, decimal) : this._loadResult(bills, this.prefixes, decimal);
  213. }
  214. }
  215. async _loadStageBillsData(tender, stage, gsDefine, auditors, filterGcl = true) {
  216. const helper = this.ctx.helper;
  217. // 加载截止上期/本期
  218. let billsData = await this.ctx.service.ledger.getData(tender.id);
  219. if (filterGcl) billsData = billsData.filter(x => { return x.b_code && x.is_leaf });
  220. const curStage = await this.ctx.service.stageBills.getLastestStageData2(tender.id, stage.id);
  221. const preStage = stage.order > 1 ? await this.ctx.service.stageBillsFinal.getFinalData(tender, stage.order - 1) : [];
  222. const loadData = [
  223. { data: curStage, fields: this.billsQueryField, prefix: '', relaId: 'lid' },
  224. { data: preStage, fields: this.billsQueryField, prefix: 'pre_', relaId: 'lid' }
  225. ];
  226. for (const dc of gsDefine.defaultCompare) {
  227. const auditor = auditors[dc];
  228. if (!auditor) continue;
  229. const auditorStage = await this.ctx.service.stageBills.getAuditorStageData2(tender.id, stage.id, auditor.times, auditor.order);
  230. loadData.push({ data: auditorStage, fields: this.billsQueryField, prefix: `r${dc}_`, relaId: 'lid' });
  231. }
  232. helper.assignRelaData(billsData, loadData);
  233. return billsData;
  234. }
  235. async _loadStagePosData(tender, stage, gsDefine, auditors) {
  236. const helper = this.ctx.helper;
  237. const posData = await this.ctx.service.pos.getPosData({tid: tender.id});
  238. const curStage = await this.ctx.service.stagePos.getLastestStageData2(tender.id, stage.id);
  239. const preStage = stage.order > 1 ? await this.ctx.service.stagePosFinal.getFinalData(tender, stage.order - 1) : [];
  240. const loadData = [
  241. { data: curStage, fields: ['qc_qty'], prefix: '', relaId: 'pid' },
  242. { data: preStage, fields: ['qc_qty'], prefix: 'pre_', relaId: 'pid' }
  243. ];
  244. for (const dc of gsDefine.defaultCompare) {
  245. const auditor = auditors[dc];
  246. if (!auditor) continue;
  247. const auditorStage = await this.ctx.service.stagePos.getAuditorStageData2(tender.id, stage.id, auditor.times, auditor.order);
  248. loadData.push({ data: auditorStage, fields: ['qc_qty'], prefix: `r${dc}_`, relaId: 'pid' });
  249. }
  250. helper.assignRelaData(posData, loadData);
  251. return posData;
  252. }
  253. async _gatherStageData(tender, stage, gsDefine) {
  254. if (!stage) return;
  255. const helper = this.ctx.helper;
  256. await this.ctx.service.stage.doCheckStage(stage);
  257. const auditors = this.getLastestAuditors(stage.auditors);
  258. const user = await this.ctx.service.projectAccount.getDataById(stage.user_id);
  259. auditors.unshift({
  260. aid: user.id, name: user.name, company: user.company, role: user.role,
  261. times: stage.curTimes, order: 0
  262. });
  263. const billsData = await this._loadStageBillsData(tender, stage, gsDefine, auditors);
  264. // 计算截止本期
  265. billsData.forEach(x => {
  266. x.end_qc_qty = helper.add(x.qc_qty, x.pre_qc_qty);
  267. x.end_qc_tp = helper.add(x.qc_tp, x.pre_qc_tp);
  268. });
  269. const posData = await this._loadStagePosData(tender, stage, gsDefine, auditors);
  270. posData.forEach(x => {
  271. x.end_qc_qty = helper.add(x.qc_qty, x.pre_qc_qty);
  272. });
  273. // 创建索引
  274. const billsIndex = {};
  275. for (const b of billsData) {
  276. billsIndex[b.id] = b;
  277. b.pos = posData.filter(x => { return x.lid === b.id; });
  278. }
  279. // 查询比较人数据
  280. this.prefixes = [];
  281. const stageChangeDetail = await this.getCurChangeDetailData(tender.id, stage.id);
  282. this.ctx.helper.saveBufferFile(JSON.stringify(stageChangeDetail, '', '\t'), this.ctx.app.baseDir + '/temp.json');
  283. for (const dc of gsDefine.defaultCompare) {
  284. if (!auditors[dc]) continue;
  285. const scd = helper.filterTimesOrderData(stageChangeDetail, ['lid', 'pid', 'cbid', 'no_value'], 'stimes', 'sorder', auditors[dc].times, auditors[dc].order);
  286. this._loadChangeDetail(billsIndex, scd, gsDefine, `r${dc}_`);
  287. this.prefixes.push(`r${dc}_`);
  288. }
  289. const finalChangeData = await this.getPreChangeDetailData(tender.id, stage.order);
  290. this._loadChangeDetail(billsIndex, finalChangeData, gsDefine, 'pre_');
  291. this._generateResult(billsData, gsDefine, tender.info.decimal);
  292. }
  293. async _gatherStageBillsData(tender, stage, gsDefine) {
  294. if (!stage) return;
  295. const helper = this.ctx.helper;
  296. await this.ctx.service.stage.doCheckStage(stage);
  297. const auditors = this.getLastestAuditors(stage.auditors);
  298. const user = await this.ctx.service.projectAccount.getDataById(stage.user_id);
  299. auditors.unshift({
  300. aid: user.id, name: user.name, company: user.company, role: user.role,
  301. times: stage.curTimes, order: 0
  302. });
  303. const billsData = await this._loadStageBillsData(tender, stage, gsDefine, auditors, false);
  304. const billsTree = new Ledger.billsTree(this.ctx, {
  305. id: 'ledger_id',
  306. pid: 'ledger_pid',
  307. order: 'order',
  308. level: 'level',
  309. rootId: -1,
  310. keys: ['id', 'ledger_id'],
  311. stageId: 'id',
  312. calcFields: ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp', 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp'],
  313. calc: function (node) {
  314. if (node.children && node.children.length === 0) {
  315. node.pre_gather_qty = helper.add(node.pre_contract_qty, node.pre_qc_qty);
  316. node.gather_qty = helper.add(node.contract_qty, node.qc_qty);
  317. node.end_contract_qty = helper.add(node.pre_contract_qty, node.contract_qty);
  318. node.end_qc_qty = helper.add(node.pre_qc_qty, node.qc_qty);
  319. node.end_gather_qty = helper.add(node.pre_gather_qty, node.gather_qty);
  320. }
  321. node.pre_gather_tp = helper.add(node.pre_contract_tp, node.pre_qc_tp);
  322. node.gather_tp = helper.add(node.contract_tp, node.qc_tp);
  323. node.end_contract_tp = helper.add(node.pre_contract_tp, node.contract_tp);
  324. node.end_qc_tp = helper.add(node.pre_qc_tp, node.qc_tp);
  325. node.end_gather_tp = helper.add(node.pre_gather_tp, node.gather_tp);
  326. for (const dc of gsDefine.defaultCompare) {
  327. const prefix = `r${dc}_`;
  328. node[prefix + 'gather_qty'] = helper.add(node[prefix + 'contract_qty'], node[prefix + 'qc_qty']);
  329. node[prefix + 'gather_tp'] = helper.add(node[prefix + 'contract_tp'], node[prefix + 'qc_tp']);
  330. }
  331. }
  332. });
  333. billsTree.loadDatas(billsData);
  334. billsTree.calculateAll();
  335. this.resultTree.loadGatherTree(billsTree, function (gatherNode, sourceNode) {
  336. gatherNode.s_qty = helper.add(gatherNode.s_qty, sourceNode.quantity);
  337. gatherNode.s_tp = helper.add(gatherNode.s_tp, sourceNode.total_price);
  338. gatherNode.s_dgn_qty1 = helper.add(gatherNode.s_dgn_qty1, sourceNode.dgn_qty1);
  339. gatherNode.s_dgn_qty2 = helper.add(gatherNode.s_dgn_qty2, sourceNode.dgn_qty2);
  340. gatherNode.s_contract_qty = helper.add(gatherNode.s_contract_qty, sourceNode.contract_qty);
  341. gatherNode.s_contract_tp = helper.add(gatherNode.s_contract_tp, sourceNode.contract_tp);
  342. gatherNode.s_qc_qty = helper.add(gatherNode.s_qc_qty, sourceNode.qc_qty);
  343. gatherNode.s_qc_tp = helper.add(gatherNode.s_qc_tp, sourceNode.qc_tp);
  344. gatherNode.s_gather_qty = helper.add(gatherNode.s_gather_qty, sourceNode.gather_qty);
  345. gatherNode.s_gather_tp = helper.add(gatherNode.s_gather_tp, sourceNode.gather_tp);
  346. gatherNode.s_pre_contract_qty = helper.add(gatherNode.s_pre_contract_qty, sourceNode.pre_contract_qty);
  347. gatherNode.s_pre_contract_tp = helper.add(gatherNode.s_pre_contract_tp, sourceNode.pre_contract_tp);
  348. gatherNode.s_pre_qc_qty = helper.add(gatherNode.s_pre_qc_qty, sourceNode.pre_qc_qty);
  349. gatherNode.s_pre_qc_tp = helper.add(gatherNode.s_pre_qc_tp, sourceNode.pre_qc_tp);
  350. gatherNode.s_pre_gather_qty = helper.add(gatherNode.s_pre_gather_qty, sourceNode.pre_gather_qty);
  351. gatherNode.s_pre_gather_tp = helper.add(gatherNode.s_pre_gather_tp, sourceNode.pre_gather_tp);
  352. gatherNode.s_end_contract_qty = helper.add(gatherNode.s_end_contract_qty, sourceNode.end_contract_qty);
  353. gatherNode.s_end_contract_tp = helper.add(gatherNode.s_end_contract_tp, sourceNode.end_contract_tp);
  354. gatherNode.s_end_qc_qty = helper.add(gatherNode.s_end_qc_qty, sourceNode.end_qc_qty);
  355. gatherNode.s_end_qc_tp = helper.add(gatherNode.s_end_qc_tp, sourceNode.end_qc_tp);
  356. gatherNode.s_end_gather_qty = helper.add(gatherNode.s_end_gather_qty, sourceNode.end_gather_qty);
  357. gatherNode.s_end_gather_tp = helper.add(gatherNode.s_end_gather_tp, sourceNode.end_gather_tp);
  358. for (const dc of gsDefine.defaultCompare) {
  359. const prefix = `r${dc}_`;
  360. gatherNode[prefix + 'contract_qty'] = helper.add(gatherNode[prefix + 'contract_qty'], sourceNode[prefix + 'contract_qty']);
  361. gatherNode[prefix + 'contract_tp'] = helper.add(gatherNode[prefix + 'contract_tp'], sourceNode[prefix + 'contract_tp']);
  362. gatherNode[prefix + 'qc_qty'] = helper.add(gatherNode[prefix + 'qc_qty'], sourceNode[prefix + 'qc_qty']);
  363. gatherNode[prefix + 'qc_tp'] = helper.add(gatherNode[prefix + 'qc_tp'], sourceNode[prefix + 'qc_tp']);
  364. gatherNode[prefix + 'gather_qty'] = helper.add(gatherNode[prefix + 'gather_qty'], sourceNode[prefix + 'gather_qty']);
  365. gatherNode[prefix + 'gather_tp'] = helper.add(gatherNode[prefix + 'gather_tp'], sourceNode[prefix + 'gather_tp']);
  366. }
  367. });
  368. }
  369. async _gatherMonthData(tender, month, defaultCompare, fun) {
  370. const stages = await this._getValidStages(tender.id);
  371. const stage = this.ctx.helper._.find(stages, {s_time: month});
  372. await fun.call(this, tender, stage, defaultCompare);
  373. }
  374. async _gatherFinalData(tender, defaultCompare, fun) {
  375. const stages = await this._getValidStages(tender.id);
  376. await fun.call(this, tender, stages[0], defaultCompare);
  377. }
  378. async _gatherCheckedFinalData(tender, defaultCompare, fun) {
  379. const stages = await this._getCheckedStages(tender.id);
  380. await fun.call(this, tender, stages[0], defaultCompare);
  381. }
  382. async _gatherIndexData(tender, index, defaultCompare, fun) {
  383. const stages = await this._getValidStages(tender.id);
  384. const stage = this.ctx.helper._.find(stages, {order: index});
  385. await fun.call(this, tender, stage, defaultCompare);
  386. }
  387. /**
  388. *
  389. * @param {Array} memFieldKeys 报表添加的指标字段
  390. * @param {object} gsDefine
  391. * @param {object} gsCustom
  392. * @returns {Promise<Array>}
  393. */
  394. async gather(memFieldKeys, gsDefine, gsCustom) {
  395. this.billsQueryField = ['qc_qty', 'qc_tp'];
  396. if (!gsDefine || !gsDefine.enable) return [];
  397. if (!gsCustom || !gsCustom.tenders || gsCustom.tenders.length === 0) return [];
  398. const gsSetting = JSON.parse(gsDefine.setting);
  399. if (!gsSetting.defaultCompare || !gsSetting.match) return[];
  400. for (const t of gsCustom.tenders) {
  401. const tender = await this.ctx.service.tender.getCheckTender(t.tid);
  402. switch (gsSetting.type) {
  403. case 'month':
  404. await this._gatherMonthData(tender, gsCustom.month, gsSetting, this._gatherStageData);
  405. break;
  406. case 'final':
  407. await this._gatherFinalData(tender, gsSetting, this._gatherStageData);
  408. break;
  409. case 'checked-final':
  410. await this._gatherCheckedFinalData(tender, gsSetting, this._gatherStageData);
  411. break;
  412. case 'stage':
  413. await this._gatherIndexData(tender, gsCustom.stage, gsSetting, this._gatherStageData);
  414. break;
  415. default: throw '未知汇总类型';
  416. }
  417. }
  418. const helper = this.ctx.helper;
  419. // 排序
  420. this.result.sort((x, y) => { return helper.compareCode(x.b_code, y.b_code); });
  421. return this.result;
  422. }
  423. async convert(tid, sid, memFieldKeys, option) {
  424. this.billsQueryField = ['qc_qty', 'qc_tp'];
  425. if (!option) return [];
  426. const setting = JSON.parse(option);
  427. if (!setting || !setting.defaultCompare) return [];
  428. const tender = await this.ctx.service.tender.getCheckTender(tid);
  429. const stage = await this.ctx.service.stage.getDataById(sid);
  430. await this._gatherStageData(tender, stage, setting);
  431. const helper = this.ctx.helper;
  432. // 排序
  433. this.result.sort((x, y) => { return helper.compareCode(x.b_code, y.b_code); });
  434. return this.result;
  435. }
  436. async gatherBills(memFieldKeys, gsDefine, gsCustom) {
  437. if (!gsDefine || !gsDefine.enable) return [];
  438. if (!gsCustom || !gsCustom.tenders || gsCustom.tenders.length === 0) return [];
  439. const gsSetting = JSON.parse(gsDefine.setting);
  440. if (!gsSetting.defaultCompare) return [];
  441. this.billsQueryField = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'];
  442. this.resultTree = new Ledger.gatherTree(this.ctx, {
  443. id: 'id',
  444. pid: 'pid',
  445. order: 'order',
  446. level: 'level',
  447. rootId: -1
  448. });
  449. for (const t of gsCustom.tenders) {
  450. const tender = await this.ctx.service.tender.getCheckTender(t.tid);
  451. switch (gsSetting.type) {
  452. case 'month':
  453. await this._gatherMonthData(tender, gsCustom.month, gsSetting, this._gatherStageBillsData);
  454. break;
  455. case 'final':
  456. await this._gatherFinalData(tender, gsSetting, this._gatherStageBillsData);
  457. break;
  458. case 'checked-final':
  459. await this._gatherCheckedFinalData(tender, gsSetting, this._gatherStageBillsData);
  460. break;
  461. case 'stage':
  462. await this._gatherIndexData(tender, gsCustom.stage, gsSetting, this._gatherStageBillsData);
  463. break;
  464. default: throw '未知汇总类型';
  465. }
  466. }
  467. this.resultTree.generateSortNodes();
  468. return this.resultTree.getDefaultDatas();
  469. }
  470. }
  471. /**
  472. * 奉建项目 定制报表
  473. * 变更过程管理表
  474. * 汇总工程量清单(区分正负变更)
  475. */
  476. class fjHelper {
  477. constructor (ctx) {
  478. this.ctx = ctx;
  479. }
  480. async _getStageBillsData(tid, sid) {
  481. const helper = this.ctx.helper;
  482. const billsData = await this.ctx.app.mysql.select(this.ctx.service.ledger.tableName, {
  483. where: { tender_id: tid, is_leaf: 1 }
  484. });
  485. const preStage = this.ctx.stage.order > 1 ? await this.ctx.service.stageBillsFinal.getFinalData(this.ctx.tender, this.ctx.stage.order - 1) : [];
  486. const curStage = this.ctx.stage.readOnly
  487. ? await this.ctx.service.stageBills.getAuditorStageData2(tid, this.ctx.stage.id, this.ctx.stage.curTimes, this.ctx.stage.curOrder)
  488. : await this.ctx.service.stageBills.getLastestStageData2(tid, this.ctx.stage.id);
  489. const bpcStage = await this.ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: this.ctx.stage.id } });
  490. this.ctx.helper.assignRelaData(billsData, [
  491. { data: curStage, fields: ['qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: '', relaId: 'lid' },
  492. { data: preStage, fields: ['qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: 'pre_', relaId: 'lid' },
  493. { data: bpcStage, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'org_price'], prefix: '', relaId: 'lid' },
  494. ]);
  495. billsData.forEach(node => {
  496. node.end_qc_qty = helper.add(node.pre_qc_qty, node.qc_qty);
  497. node.end_qc_tp = helper.sum([node.pre_qc_tp, node.qc_tp, node.qc_pc_tp]);
  498. node.final_qty = helper.add(node.quantity, node.end_qc_qty);
  499. node.final_tp = helper.add(node.total_price, node.end_qc_tp);
  500. });
  501. return billsData;
  502. }
  503. async _getStageImportChangeData(tid, sid) {
  504. const sql = 'SELECT sic.*, l.b_code, l.name, l.unit, l.unit_price, l.quantity, l.total_price' +
  505. ' FROM ' + this.ctx.service.stageImportChange.tableName + ' sic ' +
  506. ' LEFT JOIN (SELECT * FROM ' + this.ctx.service.ledger.tableName + ' WHERE tender_id = ? AND is_leaf) AS l ON sic.lid = l.id' +
  507. ' WHERE sic.tid = ? AND sic.sid <= ?';
  508. return await this.ctx.app.mysql.query(sql, [tid, tid, sid]);
  509. }
  510. convertChangeProgress(data, sid) {
  511. const helper = this.ctx.helper, tpDecimal = this.ctx.tender.info.decimal.tp;
  512. const bills = [];
  513. for (const d of data) {
  514. let b = bills.find(x => {
  515. return x.b_code === d.b_code && x.name === d.name && x.unit === d.unit && x.unit_price === d.unit_price;
  516. });
  517. if (!b) {
  518. b = { b_code: d.b_code, name: d.name, unit: d.unit, unit_price: d.unit_price, ledgerSource: [] };
  519. bills.push(b);
  520. }
  521. const ls = b.ledgerSource.find(x => { return x.lid === d.lid; });
  522. if (!ls) b.ledgerSource.push({lid: d.lid, quantity: d.quantity, total_price: d.total_price });
  523. const field = (d.sid < sid ? 'pre_' : '') + (d.rela_qty > 0 ? 'positive_' : 'negative_') + 'qc_qty';
  524. b[field] = this.ctx.helper.add(b[field], d.rela_qty);
  525. }
  526. bills.sort((a, b) => { return helper.compareCode(a.b_code, b.b_code); });
  527. const result = [];
  528. for (const b of bills) {
  529. b.pre_positive_qc_tp = helper.mul(b.unit_price, b.pre_positive_qc_qty, tpDecimal);
  530. b.pre_negative_qc_tp = helper.mul(b.unit_price, b.pre_negative_qc_qty, tpDecimal);
  531. b.positive_qc_tp = helper.mul(b.unit_price, b.positive_qc_qty, tpDecimal);
  532. b.negative_qc_tp = helper.mul(b.unit_price, b.negative_qc_qty, tpDecimal);
  533. b.end_positive_qc_qty = helper.add(b.pre_positive_qc_qty, b.positive_qc_qty);
  534. b.end_positive_qc_tp = helper.add(b.pre_positive_qc_tp, b.positive_qc_tp);
  535. b.end_negative_qc_qty = helper.add(b.pre_negative_qc_qty, b.negative_qc_qty);
  536. b.end_negative_qc_tp = helper.add(b.pre_negative_qc_tp, b.negative_qc_tp);
  537. b.final_qty = helper.add(b.quantity, helper.add(b.end_positive_qc_qty, b.end_negative_qc_qty));
  538. b.final_qty = helper.add(b.total_price, helper.add(b.end_positive_qc_tp, b.end_negative_qc_tp));
  539. result.push({
  540. b_code: b.b_code, name: b.name, unit: b.unit, unit_price: b.unit_price,
  541. quantity: b.quantity, total_price: b.total_price,
  542. pre_qc_qty: b.pre_positive_qc_qty, pre_qc_tp: b.pre_positive_qc_tp,
  543. qc_qty: b.positive_qc_qty, qc_tp: b.positive_qc_tp,
  544. end_qc_qty: b.end_positive_qc_qty, end_qc_tp: b.end_positive_qc_tp,
  545. final_qty: b.final_qty, final_tp: b.final_tp,
  546. minus: 0,
  547. });
  548. result.push({
  549. b_code: b.b_code, name: b.name, unit: b.unit, unit_price: b.unit_price,
  550. quantity: b.quantity, total_price: b.total_price,
  551. pre_qc_qty: b.pre_negative_qc_tp, pre_qc_tp: b.pre_negative_qc_tp,
  552. qc_qty: b.negative_qc_qty, qc_tp: b.negative_qc_tp,
  553. end_qc_qty: b.end_negative_qc_qty, end_qc_tp: b.end_negative_qc_tp,
  554. final_qty: b.final_qty, final_tp: b.final_tp,
  555. minus: 1,
  556. });
  557. }
  558. return result;
  559. }
  560. convertChangeProgress1(stageBills, stageImportChange, sid) {
  561. const helper = this.ctx.helper, tpDecimal = this.ctx.tender.info.decimal.tp;
  562. const bills = [];
  563. for (const sb of stageBills) {
  564. if (!sb.b_code) continue;
  565. let b = bills.find(x => { return x.b_code === sb.b_code && x.name === sb.name && x.unit === sb.unit && x.unit_price === sb.unit_price; });
  566. if (!b) {
  567. b = { b_code: sb.b_code, name: sb.name, unit: sb.unit, unit_price: sb.unit_price, org_price: sb.org_price, ledgerSource: [] };
  568. bills.push(b);
  569. }
  570. const ls = b.ledgerSource.find(x => { return x.lid === sb.lid; });
  571. if (!ls) b.ledgerSource.push({
  572. lid: sb.id,
  573. quantity: sb.quantity, total_price: sb.total_price,
  574. final_qty: sb.final_qty, final_tp: sb.final_tp,
  575. });
  576. }
  577. bills.sort((a, b) => { return helper.compareCode(a.b_code, b.b_code); });
  578. for (const d of stageImportChange) {
  579. const b = bills.find(x => { return x.ledgerSource.findIndex(y => { return y.lid === d.lid; }) >= 0; });
  580. if (!b) continue;
  581. const field = (d.sid < sid ? 'pre_' : '') + (d.rela_qty > 0 ? 'positive_' : 'negative_') + 'qc_qty';
  582. const minusField = (d.sid < sid ? 'pre_c_' : 'c_') + (d.rela_minus > 0 ? 'minus_' : '') + 'qc_qty';
  583. b[field] = this.ctx.helper.add(b[field], d.rela_qty);
  584. b[minusField] = this.ctx.helper.add(b[minusField], d.rela_qty);
  585. }
  586. const result = [], changeSum = {};
  587. for (const b of bills) {
  588. b.quantity = helper.sum(b.ledgerSource.map(x => { return x.quantity; }));
  589. b.total_price = helper.sum(b.ledgerSource.map(x => { return x.total_price; }));
  590. b.final_qty = helper.sum(b.ledgerSource.map(x => { return x.final_qty; }));
  591. b.final_tp = helper.sum(b.ledgerSource.map(x => { return x.final_tp; }));
  592. if (b.org_price) {
  593. b.pre_positive_qc_tp = helper.mul(b.org_price, b.pre_positive_qc_qty, tpDecimal);
  594. b.pre_negative_qc_tp = helper.mul(b.org_price, b.pre_negative_qc_qty, tpDecimal);
  595. b.positive_qc_pc_tp = helper.sub(helper.mul(b.unit_price, b.pre_positive_qc_qty, tpDecimal), b.pre_positive_qc_tp);
  596. b.negative_qc_pc_tp = helper.sub(helper.mul(b.unit_price, b.pre_negative_qc_qty, tpDecimal), b.pre_negative_qc_tp);
  597. } else {
  598. b.pre_positive_qc_tp = helper.mul(b.unit_price, b.pre_positive_qc_qty, tpDecimal);
  599. b.pre_negative_qc_tp = helper.mul(b.unit_price, b.pre_negative_qc_qty, tpDecimal);
  600. b.positive_qc_pc_tp = 0;
  601. b.negative_qc_pc_tp = 0;
  602. }
  603. b.positive_qc_tp = helper.mul(b.unit_price, b.positive_qc_qty, tpDecimal);
  604. b.negative_qc_tp = helper.mul(b.unit_price, b.negative_qc_qty, tpDecimal);
  605. b.end_positive_qc_qty = helper.add(b.pre_positive_qc_qty, b.positive_qc_qty);
  606. b.end_positive_qc_tp = helper.add(helper.add(b.pre_positive_qc_tp, b.positive_qc_tp), b.positive_qc_pc_tp);
  607. b.end_negative_qc_qty = helper.add(b.pre_negative_qc_qty, b.negative_qc_qty);
  608. b.end_negative_qc_tp = helper.add(helper.add(b.pre_negative_qc_tp, b.negative_qc_tp), b.negative_qc_pc_tp);
  609. if (b.org_price) {
  610. b.pre_c_qc_tp = helper.mul(b.org_price, b.pre_c_qc_qty, tpDecimal);
  611. b.pre_c_minus_qc_tp = helper.mul(b.org_price, b.pre_c_minus_qc_qty, tpDecimal);
  612. b.c_qc_pc_tp = helper.sub(helper.mul(b.unit_price, b.pre_c_qc_qty, tpDecimal), b.pre_c_qc_tp);
  613. b.c_minus_qc_pc_tp = helper.sub(helper.mul(b.unit_price, b.pre_c_minus_qc_qty, tpDecimal), b.pre_c_minus_qc_tp);
  614. } else {
  615. b.pre_c_qc_tp = helper.mul(b.unit_price, b.pre_c_qc_qty, tpDecimal);
  616. b.pre_c_minus_qc_tp = helper.mul(b.unit_price, b.pre_c_minus_qc_qty, tpDecimal);
  617. b.c_positive_qc_pc_tp = 0;
  618. b.c_negative_qc_pc_tp = 0;
  619. }
  620. b.c_qc_tp = helper.mul(b.unit_price, b.c_qc_qty, tpDecimal);
  621. b.c_minus_qc_tp = helper.mul(b.unit_price, b.c_minus_qc_qty, tpDecimal);
  622. b.end_c_qc_qty = helper.add(b.pre_c_qc_qty, b.c_qc_qty);
  623. b.end_c_qc_tp = helper.add(helper.add(b.pre_c_qc_tp, b.c_qc_tp), b.c_qc_pc_tp);
  624. b.end_c_minus_qc_qty = helper.add(b.pre_c_minus_qc_qty, b.c_minus_qc_qty);
  625. b.end_c_minus_qc_tp = helper.add(helper.add(b.pre_c_minus_qc_tp, b.c_minus_qc_tp), b.c_minus_qc_pc_tp);
  626. // 统计合计
  627. changeSum.pre_c_tp = helper.add(changeSum.pre_c_tp, b.pre_c_qc_tp);
  628. changeSum.c_tp = helper.add(changeSum.c_tp, b.c_qc_tp);
  629. changeSum.c_pc_tp = helper.add(changeSum.c_pc_tp, b.c_qc_pc_tp);
  630. changeSum.end_c_tp = helper.add(changeSum.end_c_tp, b.end_c_qc_tp);
  631. changeSum.pre_c_minus_tp = helper.add(changeSum.pre_c_minus_tp, b.pre_c_minus_qc_tp);
  632. changeSum.c_minus_tp = helper.add(changeSum.c_minus_tp, b.c_minus_qc_tp);
  633. changeSum.c_minus_pc_tp = helper.add(changeSum.c_minus_pc_tp, b.c_minus_qc_pc_tp);
  634. changeSum.end_c_minus_tp = helper.add(changeSum.end_c_minus_tp, b.end_c_minus_qc_tp);
  635. result.push({
  636. b_code: b.b_code, name: b.name, unit: b.unit, unit_price: b.unit_price,
  637. quantity: b.quantity, total_price: b.total_price,
  638. pre_qc_qty: b.pre_positive_qc_qty, pre_qc_tp: b.pre_positive_qc_tp,
  639. qc_qty: b.positive_qc_qty, qc_tp: b.positive_qc_tp, qc_pc_tp: b.positive_qc_pc_tp,
  640. end_qc_qty: b.end_positive_qc_qty, end_qc_tp: b.end_positive_qc_tp,
  641. final_qty: b.final_qty, final_tp: b.final_tp,
  642. minus: 0,
  643. });
  644. result.push({
  645. b_code: b.b_code, name: b.name, unit: b.unit, unit_price: b.unit_price,
  646. quantity: b.quantity, total_price: b.total_price,
  647. pre_qc_qty: b.pre_negative_qc_qty, pre_qc_tp: b.pre_negative_qc_tp,
  648. qc_qty: b.negative_qc_qty, qc_tp: b.negative_qc_tp, qc_pc_tp: b.negative_qc_pc_tp,
  649. end_qc_qty: b.end_negative_qc_qty, end_qc_tp: b.end_negative_qc_tp,
  650. final_qty: b.final_qty, final_tp: b.final_tp,
  651. minus: 1,
  652. });
  653. }
  654. return { mem_fj_change_progress: result, mem_fj_change_sum: [changeSum] };
  655. }
  656. async getChangeProgressData(tid, sid) {
  657. await this.ctx.service.stage.checkStage(sid);
  658. const stageBills = await this._getStageBillsData(tid, sid);
  659. const stageImportChange = await this._getStageImportChangeData(tid, sid);
  660. return this.convertChangeProgress1(stageBills, stageImportChange, sid);
  661. }
  662. }
  663. module.exports = {
  664. jhHelper,
  665. fjHelper,
  666. };