rptCustomData.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. 'use strict';
  2. /**
  3. * 定制报表 注意不做任何混用,也不做任何继承
  4. *
  5. * @author Mai
  6. * @date
  7. * @version
  8. */
  9. const auditConst = require('../const/audit');
  10. /**
  11. * 季华项目 定制报表
  12. * 汇总表,流水汇总2个标段(N个),汇总到期,每期汇总3个人的数据(3个),工程量清单流水表,并根据截至本期变更令使用情况筛选
  13. *
  14. * 借用 通用汇总标段选的界面
  15. * 故配置可与汇总标段选择相同
  16. *
  17. * define: {
  18. * "title": "请选择汇总的标段", "type": "month/final/checked-final/stage",
  19. * "defaultCompare": [1, 2, 3], // 结果按序 rn_qty, rn_tp
  20. * "match": { "quality": [2, 3], "qty": "<0" }, // class根据变更类型过滤,qty根据数量过滤
  21. * "merge": true,
  22. * }
  23. * defaultCompare为默认选择的审批人,0为原报,1-N为1-N审
  24. * match为保留的类型
  25. * 如需要用户选择审批人,则应配置selectCompare(目前不可用,不可配置,如需使用,则需要额外界面),为后期可能的变动预留
  26. *
  27. */
  28. class jhHelper {
  29. constructor (ctx) {
  30. this.ctx = ctx;
  31. this.result = [];
  32. }
  33. async _getValidStages(tenderId) {
  34. const stages = await this.ctx.service.stage.db.select(this.ctx.service.stage.tableName, {
  35. where: { tid: tenderId },
  36. orders: [['order', 'desc']],
  37. });
  38. if (stages.length !== 0) {
  39. const lastStage = stages[0];
  40. if (lastStage.status === auditConst.stage.status.uncheck && lastStage.user_id !== this.ctx.session.sessionUser.accountId) {
  41. stages.splice(0, 1);
  42. }
  43. }
  44. return stages;
  45. }
  46. async _getCheckedStages(tenderId) {
  47. const stages = await this.db.select(this.ctx.service.stage.tableName, {
  48. where: { tid: tenderId },
  49. orders: [['order', 'desc']],
  50. });
  51. if (stages.length !== 0) {
  52. const lastStage = stages[0];
  53. if (lastStage.status !== auditConst.stage.status.checked) {
  54. stages.splice(0, 1);
  55. }
  56. }
  57. return stages;
  58. }
  59. /**
  60. * 查询本期所有变更明细
  61. * @param tid
  62. * @param sid
  63. * @returns {Promise<void>}
  64. */
  65. async getCurChangeDetailData(tid, sid) {
  66. 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' +
  67. ' Left Join ' + this.ctx.service.change.tableName + ' c ON sc.cid = c.cid' +
  68. ' WHERE sc.tid = ? and sc.sid = ?';
  69. return await this.ctx.service.stageChange.db.query(sql, [tid, sid]);
  70. }
  71. async getPreChangeDetailData(tid, sOrder) {
  72. 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' +
  73. ' Left Join ' + this.ctx.service.change.tableName + ' c ON sc.cid = c.cid' +
  74. ' Left Join ' + this.ctx.service.stage.tableName + ' s ON sc.sid = s.id' +
  75. ' WHERE sc.tid = ? and s.order < ?';
  76. return await this.ctx.service.stageChangeFinal.db.query(sql, [tid, sOrder]);
  77. }
  78. getLastestAuditors(auditors) {
  79. const index = {};
  80. for (const auditor of auditors) {
  81. if (!index[auditor.aid] || auditor.order > index[auditor.aid].order) index[auditor.aid] = auditor;
  82. }
  83. const result = [];
  84. for (const i in index) {
  85. result.push(index[i]);
  86. }
  87. result.sort((x, y) => { return x.order - y.order; });
  88. return result;
  89. }
  90. _loadChangeDetail(billsIndex, changeDetail, gsDefine, prefix) {
  91. for (const cd of changeDetail) {
  92. if (!cd.qty) continue;
  93. let match = false;
  94. for (const m of gsDefine.match) {
  95. if (m.quality === cd.c_quality && ((m.minus && cd.qty < 0) || (!m.minus && cd.qty > 0))) match = true;
  96. }
  97. if (!match) continue;
  98. const bills = billsIndex[cd.lid];
  99. if (!bills) continue;
  100. if (!bills[prefix + 'cd']) bills[prefix + 'cd'] = [];
  101. bills[prefix + 'cd'].push(cd);
  102. if (cd.pid) {
  103. const pos = bills.pos.find(x => {return x.id === cd.pid});
  104. if (pos) {
  105. if (!pos[prefix + 'cd']) pos[prefix + 'cd'] = [];
  106. pos[prefix + 'cd'].push(cd);
  107. }
  108. }
  109. }
  110. }
  111. _loadMergeResult(bills, prefixes) {
  112. const rst = {
  113. id: bills.id,
  114. tid: bills.tender_id,
  115. b_code: bills.b_code,
  116. name: bills.name,
  117. unit: bills.unit,
  118. unit_price: bills.unit_price
  119. };
  120. if (bills.pos && bills.pos.length > 0) {
  121. for (const p of bills.pos) {
  122. let gather = false;
  123. if (p.pre_cd && p.pre_cd.length > 0) gather = true;
  124. for (const prefix of prefixes) {
  125. if (p[prefix + 'cd'] && p[prefix + 'cd'].length > 0) gather = true;
  126. }
  127. if (gather) {
  128. rst.qc_qty = this.ctx.helper.add(rst.qc_qty, p.qc_qty);
  129. rst.qc_tp = this.ctx.helper.add(rst.qc_qty, p.qc_tp);
  130. rst.pre_qc_qty = this.ctx.helper.add(rst.pre_qc_qty, p.pre_qc_qty);
  131. rst.pre_qc_tp = this.ctx.helper.add(rst.pre_qc_tp, p.pre_qc_tp);
  132. rst.end_qc_qty = this.ctx.helper.add(rst.end_qc_qty, p.end_qc_qty);
  133. rst.end_qc_tp = this.ctx.helper.add(rst.end_qc_tp, p.end_qc_tp);
  134. for (const prefix of prefixes) {
  135. rst[prefix + 'qc_qty'] = this.ctx.helper.add(rst[prefix + 'qc_qty'], p[prefix + 'qc_qty']);
  136. }
  137. }
  138. }
  139. for (const prefix of prefixes) {
  140. rst[prefix + 'qc_tp'] = this.ctx.helper.mul(rst.unit_price, rst[prefix + 'qc_qty'], 2);
  141. }
  142. } else {
  143. if (bills.b_code === '203-1-a') console.log(bills);
  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) {
  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 = p.qc_tp;
  174. rst.pre_qc_qty = p.pre_qc_qty;
  175. rst.pre_qc_tp = p.pre_qc_tp;
  176. rst.end_qc_qty = p.end_qc_qty;
  177. rst.end_qc_tp = p.end_qc_tp;
  178. for (const prefix of prefixes) {
  179. rst[prefix + 'qc_qty'] = p[prefix + 'qc_qty'];
  180. rst[prefix + 'qc_tp'] = p[prefix + 'qc_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) {
  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) : this._loadResult(bills, this.prefixes);
  213. }
  214. }
  215. async _loadStageBillsData(tender, stage, gsDefine, auditors) {
  216. const helper = this.ctx.helper;
  217. // 加载截止上期/本期
  218. let billsData = await this.ctx.service.ledger.getData(tender.id);
  219. billsData = billsData.filter(x => { return x.b_code && x.is_leaf });
  220. const curStage = await this.ctx.service.stageBills.getLastestStageData(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: ['qc_qty', 'qc_tp'], prefix: '', relaId: 'lid' },
  224. { data: preStage, fields: ['qc_qty', 'qc_tp'], prefix: 'pre_', relaId: 'lid' }
  225. ];
  226. for (const dc of gsDefine.defaultCompare) {
  227. const auditor = auditors[dc];
  228. const auditorStage = await this.ctx.service.stageBills.getAuditorStageData(tender.id, stage.id, auditor.times, auditor.order);
  229. loadData.push({ data: auditorStage, fields: ['qc_qty', 'qc_tp'], prefix: `r${dc}_`, relaId: 'lid' });
  230. }
  231. helper.assignRelaData(billsData, loadData);
  232. // 计算截止本期
  233. billsData.forEach(x => {
  234. x.end_qc_qty = helper.add(x.qc_qty, x.pre_qc_qty);
  235. x.end_qc_tp = helper.add(x.qc_tp, x.pre_qc_tp);
  236. });
  237. return billsData;
  238. }
  239. async _loadStagePosData(tender, stage, gsDefine, auditors) {
  240. const helper = this.ctx.helper;
  241. const posData = await this.ctx.service.pos.getPosData({tid: tender.id});
  242. const curStage = await this.ctx.service.stagePos.getLastestStageData2(tender.id, stage.id);
  243. const preStage = stage.order > 1 ? await this.ctx.service.stagePosFinal.getFinalData(tender, stage.order - 1) : [];
  244. const loadData = [
  245. { data: curStage, fields: ['qc_qty'], prefix: '', relaId: 'pid' },
  246. { data: preStage, fields: ['qc_qty'], prefix: 'pre_', relaId: 'pid' }
  247. ];
  248. for (const dc of gsDefine.defaultCompare) {
  249. const auditor = auditors[dc];
  250. const auditorStage = await this.ctx.service.stagePos.getAuditorStageData2(tender.id, stage.id, auditor.times, auditor.order);
  251. loadData.push({ data: auditorStage, fields: ['qc_qty'], prefix: `r${dc}_`, relaId: 'pid' });
  252. }
  253. helper.assignRelaData(posData, loadData);
  254. posData.forEach(x => {
  255. x.end_qc_qty = helper.add(x.qc_qty, x.pre_qc_qty);
  256. });
  257. return posData;
  258. }
  259. async _gatherStageData(tender, stage, gsDefine) {
  260. if (!stage) return;
  261. const helper = this.ctx.helper;
  262. await this.ctx.service.stage.doCheckStage(stage);
  263. const auditors = this.getLastestAuditors(stage.auditors);
  264. const billsData = await this._loadStageBillsData(tender, stage, gsDefine, auditors);
  265. const posData = await this._loadStagePosData(tender, stage, gsDefine, auditors);
  266. // 创建索引
  267. const billsIndex = {};
  268. for (const b of billsData) {
  269. billsIndex[b.id] = b;
  270. b.pos = posData.filter(x => { return x.lid === b.id; });
  271. b.pos.forEach(x => {
  272. x.qc_tp = helper.mul(b.unit_price, x.qc_qty, 2);
  273. x.pre_qc_tp = helper.mul(b.unit_price, x.pre_qc_qty, 2);
  274. x.end_qc_tp = helper.add(x.qc_tp, x.pre_qc_tp);
  275. })
  276. }
  277. // 查询比较人数据
  278. this.prefixes = [];
  279. const stageChangeDetail = await this.getCurChangeDetailData(tender.id, stage.id);
  280. this.ctx.helper.saveBufferFile(JSON.stringify(stageChangeDetail, '', '\t'), this.ctx.app.baseDir + '/temp.json');
  281. for (const dc of gsDefine.defaultCompare) {
  282. const scd = helper.filterTimesOrderData(stageChangeDetail, ['lid', 'pid', 'cid', 'cbid'], 'stimes', 'sorder', auditors[dc].times, auditors[dc].order);
  283. this._loadChangeDetail(billsIndex, scd, gsDefine, `r${dc}_`);
  284. this.prefixes.push(`r${dc}_`);
  285. }
  286. const finalChangeData = await this.getPreChangeDetailData(tender.id, stage.order);
  287. this._loadChangeDetail(billsIndex, finalChangeData, gsDefine, 'pre_');
  288. this._generateResult(billsData, gsDefine);
  289. }
  290. async _gatherMonthData(tender, month, defaultCompare) {
  291. const stages = await this._getValidStages(tender.id);
  292. const stage = this.ctx.helper._.find(stages, {s_time: month});
  293. await this._gatherStageData(tender, stage, defaultCompare);
  294. }
  295. async _gatherFinalData(tender, defaultCompare) {
  296. const stages = await this._getValidStages(tender.id);
  297. await this._gatherStageData(tender, stages[0], defaultCompare);
  298. }
  299. async _gatherCheckedFinalData(tender, defaultCompare) {
  300. const stages = await this._getCheckedStages(tender.id);
  301. await this._gatherStageData(tender, stages[0], defaultCompare);
  302. }
  303. async _gatherIndexData(tender, index, defaultCompare) {
  304. const stages = await this._getValidStages(tender.id);
  305. const stage = this.ctx.helper._.find(stages, {order: index});
  306. await this._gatherStageData(tender, stage, defaultCompare);
  307. }
  308. /**
  309. *
  310. * @param {Array} memFieldKeys 报表添加的指标字段
  311. * @param {object} gsDefine
  312. * @param {object} gsCustom
  313. * @returns {Promise<Array>}
  314. */
  315. async gather(memFieldKeys, gsDefine, gsCustom) {
  316. if (!gsDefine || !gsDefine.enable) return [];
  317. if (!gsCustom || !gsCustom.tenders || gsCustom.tenders.length === 0) return [];
  318. const gsSetting = JSON.parse(gsDefine.setting);
  319. if (!gsSetting.defaultCompare || !gsSetting.match) return[];
  320. for (const t of gsCustom.tenders) {
  321. const tender = await this.ctx.service.tender.getCheckTender(t.tid);
  322. switch (gsSetting.type) {
  323. case 'month':
  324. await this._gatherMonthData(tender, gsCustom.month, gsSetting);
  325. break;
  326. case 'final':
  327. await this._gatherFinalData(tender, gsSetting);
  328. break;
  329. case 'checked-final':
  330. await this._gatherCheckedFinalData(tender, gsSetting);
  331. break;
  332. case 'stage':
  333. await this._gatherIndexData(tender, gsCustom.stage, gsSetting);
  334. break;
  335. default: throw '未知汇总类型';
  336. }
  337. }
  338. const helper = this.ctx.helper;
  339. // 排序
  340. this.result.sort((x, y) => { return helper.compareCode(x.b_code, y.b_code); });
  341. // console.log(this.result);
  342. return this.result;
  343. }
  344. async convert(tid, sid, memFieldKeys, setting) {
  345. if (!setting || !setting.defaultCompare) return [];
  346. const tender = await this.ctx.service.tender.getCheckTender(tid);
  347. const stage = await this.ctx.service.stage.getDataById(sid);
  348. await this._gatherStageData(tender, stage, { defaultCompare: setting.defaultCompare });
  349. }
  350. }
  351. module.exports = {
  352. jhHelper,
  353. };