advance.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. 'use strict';
  2. const auditConst = require('../const/audit').advance;
  3. const advanceConst = require('../const/advance');
  4. const path = require('path');
  5. const fs = require('fs');
  6. module.exports = app => {
  7. class Advance extends app.BaseService {
  8. constructor(ctx) {
  9. super(ctx);
  10. this.tableName = 'advance_pay';
  11. }
  12. /**
  13. * 获取预付款列表
  14. * @param {Number} tid - 标段id
  15. * @param {Number} type - 预付款类型
  16. * @param {Number} decimal - 小数位数
  17. * @param {Number} advancePayTotal - 预付款总额
  18. */
  19. async getAdvanceList(tid, type, decimal, advancePayTotal) {
  20. this.initSqlBuilder();
  21. this.sqlBuilder.setAndWhere('tid', {
  22. value: tid,
  23. operate: '=',
  24. });
  25. this.sqlBuilder.setAndWhere('type', {
  26. value: type,
  27. operate: '=',
  28. });
  29. if (this.ctx.session.sessionUser.accountId !== this.ctx.tender.data.user_id && !this.ctx.tender.isTourist && !this.ctx.session.sessionUser.is_admin) {
  30. this.sqlBuilder.setAndWhere('status', {
  31. value: auditConst.status.uncheck,
  32. operate: '!=',
  33. });
  34. }
  35. this.sqlBuilder.orderBy = [['order', 'desc']];
  36. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  37. const advance = await this.db.query(sql, sqlParam);
  38. let isLastItem = false;
  39. for (const item of advance) {
  40. let s1,
  41. s3;
  42. const s2 = item.prev_amount.toString().split('.')[1];
  43. isLastItem = this.ctx.helper.add(item.cur_amount, item.prev_amount) === advancePayTotal;
  44. item.pay_ratio = this.ctx.helper.mul(this.ctx.helper.div(item.cur_amount, advancePayTotal), 100, 2) || 0;
  45. if (item.status === auditConst.status.uncheck || item.status === auditConst.status.checkNo) {
  46. const cur_amount = item.cur_amount || 0;
  47. s1 = parseFloat(cur_amount).toString().split('.')[1];
  48. s3 = parseFloat(this.ctx.helper.add(cur_amount, item.prev_amount)).toString().split('.')[1];
  49. isLastItem && (s3 = advancePayTotal.toString().split('.')[1]);
  50. item.cur_amount = this.ctx.helper.formatMoney(cur_amount, ',', isLastItem ? s1 && s1.length || 0 : 2);
  51. item.prev_total_amount = this.ctx.helper.formatMoney(this.ctx.helper.add(cur_amount, item.prev_amount), ',', isLastItem ? s3 && s3.length || 0 : 2);
  52. } else {
  53. s1 = item.cur_amount && item.cur_amount.toString().split('.')[1];
  54. s3 = item.prev_total_amount.toString().split('.')[1];
  55. item.cur_amount = this.ctx.helper.formatMoney(item.cur_amount, ',', s1 && s1.length || 0);
  56. item.prev_total_amount = this.ctx.helper.formatMoney(item.prev_total_amount, ',', s3 && s3.length || 0);
  57. }
  58. item.prev_amount = this.ctx.helper.formatMoney(item.prev_amount, ',', s2 && s2.length || 0);
  59. item.curAuditor = await this.ctx.service.advanceAudit.getAuditorByStatus(item.id, item.status, item.times);
  60. if (item.status === auditConst.status.checkNoPre) {
  61. item.curAuditor2 = await this.ctx.service.advanceAudit.getAuditorByStatus(item.id, auditConst.status.checking);
  62. }
  63. item.fileList = await this.ctx.service.advanceFile.getAdvanceFiles({ vid: item.id });
  64. }
  65. return advance;
  66. }
  67. // 获取预付款列表(直接获取,报表用)
  68. async getAdvanceListDirectly(tid, type = null) {
  69. this.initSqlBuilder();
  70. this.sqlBuilder.setAndWhere('tid', {
  71. value: tid,
  72. operate: '=',
  73. });
  74. if (type) {
  75. this.sqlBuilder.setAndWhere('type', {
  76. value: type,
  77. operate: '=',
  78. });
  79. }
  80. if (this.ctx.session.sessionUser.accountId !== this.ctx.tender.data.user_id && !this.ctx.tender.isTourist) {
  81. this.sqlBuilder.setAndWhere('status', {
  82. value: auditConst.status.uncheck,
  83. operate: '!=',
  84. });
  85. }
  86. this.sqlBuilder.orderBy = [['order', 'desc']];
  87. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  88. // console.log(sql);
  89. // console.log(sqlParam);
  90. const advance = await this.db.query(sql, sqlParam);
  91. return advance;
  92. }
  93. /**
  94. * 获取预付款最新一期
  95. * @param {Number} tid 标段id
  96. * @param {String} type 类型: 开工预付款|材料预付款 (0|1)
  97. * @param {Boolean} includeUnCheck 包括未上报的
  98. * @return {Promise<*>} 实例结果集
  99. */
  100. async getLastestAdvance(tid, type, includeUnCheck = false) {
  101. this.initSqlBuilder();
  102. this.sqlBuilder.setAndWhere('tid', {
  103. value: tid,
  104. operate: '=',
  105. });
  106. this.sqlBuilder.setAndWhere('type', {
  107. value: type,
  108. operate: '=',
  109. });
  110. if (!includeUnCheck) {
  111. this.sqlBuilder.setAndWhere('status', {
  112. value: auditConst.status.uncheck,
  113. operate: '!=',
  114. });
  115. }
  116. this.sqlBuilder.orderBy = [['order', 'desc']];
  117. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  118. const advance = await this.db.queryOne(sql, sqlParam);
  119. return advance;
  120. }
  121. async getSumAdvance(tid) {
  122. const sql = 'Select sum(cur_amount) as tp From ' + this.tableName + ' where tid = ?';
  123. const result = await this.db.queryOne(sql, [tid]);
  124. return result ? result.tp || 0 : 0;
  125. }
  126. /**
  127. * 创建一条新的记录
  128. * @param {String} type 类型: 开工预付款|材料预付款 (start|material)
  129. * @return {Promise<*>} 插入结果集
  130. */
  131. async createRecord(type) {
  132. const { ctx } = this;
  133. const uid = ctx.session.sessionUser.accountId;
  134. const tid = ctx.tender.id;
  135. let latestOrder = await this.getLastestAdvance(tid, type, true);
  136. if (latestOrder && latestOrder.status === auditConst.status.uncheck) {
  137. return '';
  138. }
  139. if (!latestOrder) {
  140. latestOrder = {
  141. order: 1,
  142. prev_amount: 0,
  143. prev_total_amount: 0,
  144. };
  145. } else {
  146. latestOrder.order = latestOrder.order + 1;
  147. }
  148. const record = await this.db.insert(this.tableName, { type, uid, tid, status: auditConst.status.uncheck, order: latestOrder.order, prev_amount: latestOrder.prev_total_amount, prev_total_amount: latestOrder.prev_total_amount, pay_time: new Date() });
  149. const auditors = await ctx.service.advanceAudit.getAuditGroupByList(latestOrder.id, latestOrder.times);
  150. for (let idx = 0; idx < auditors.length; idx++) {
  151. const { audit_id } = auditors[idx];
  152. await ctx.service.advanceAudit.db.insert(ctx.service.advanceAudit.tableName, {
  153. tid: latestOrder.tid, audit_id, type: latestOrder.type, vid: record.insertId, times: 1, order: idx + 1, status: 1, create_time: new Date(),
  154. });
  155. }
  156. // auditors.forEach(async (auditor, idx) => {
  157. // const { audit_id } = auditor;
  158. // await ctx.service.advanceAudit.db.insert(ctx.service.advanceAudit.tableName, {
  159. // tid: latestOrder.tid, audit_id, type: latestOrder.type, vid: record.insertId, times: 1, order: idx + 1, status: 1, create_time: new Date(),
  160. // });
  161. // });
  162. return await this.getDataById(record.insertId);
  163. }
  164. /**
  165. * 获取上一期预付款记录
  166. * @param {Number} tid 标段id
  167. * @param {Number} type 预付款类型
  168. */
  169. async getPreviousRecord(tid, type) {
  170. this.initSqlBuilder();
  171. this.sqlBuilder.setAndWhere('tid', {
  172. value: tid,
  173. operate: '=',
  174. });
  175. this.sqlBuilder.setAndWhere('type', {
  176. value: type,
  177. operate: '=',
  178. });
  179. this.sqlBuilder.setAndWhere('order', {
  180. value: this.ctx.advance.order - 1,
  181. operate: '=',
  182. });
  183. this.sqlBuilder.orderBy = [['order', 'desc']];
  184. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  185. return await this.db.queryOne(sql, sqlParam);
  186. }
  187. /**
  188. * 计算列表进度条所需数据
  189. * @param {Object} latest 最新期的数据
  190. * @param {Number} payTotal 预付款金额总数
  191. * @return {Object} progress所需数据
  192. */
  193. async calcProgress(latest, payTotal) {
  194. const { ctx } = this;
  195. if (!latest) {
  196. latest = { prev_total_amount: 0, prev_amount: 0, cur_amount: 0 };
  197. }
  198. const surplus = ctx.helper.sub(payTotal, latest.prev_total_amount || 0);
  199. const p_ratio = ctx.helper.mul(ctx.helper.div(latest.prev_amount || 0, payTotal), 100, 2); // 截止上期金额总数
  200. const c_ratio = ctx.helper.mul(ctx.helper.div(latest.cur_amount || 0, payTotal), 100, 2); // 截止本期金额总数
  201. const s_ratio = ctx.helper.mul(ctx.helper.div(surplus, payTotal), 100, 2); // 剩余金额总数
  202. return {
  203. p_amount: latest.prev_amount,
  204. c_amount: latest.cur_amount,
  205. s_amount: surplus,
  206. p_ratio,
  207. c_ratio,
  208. s_ratio,
  209. };
  210. }
  211. /**
  212. * 更新预付款记录
  213. * @param {Object} payload 载荷
  214. * @param {Number} id 预付款id
  215. */
  216. async updateAdvance(payload, id) {
  217. const { ctx } = this;
  218. if (!payload.pay_time) {
  219. const prevRecord = await this.getPreviousRecord(ctx.tender.id, ctx.advance.type) || { prev_total_amount: 0 };
  220. const { cur_amount } = payload;
  221. payload.prev_total_amount = ctx.helper.add(cur_amount, prevRecord.prev_total_amount);
  222. } else {
  223. payload.pay_time = new Date(payload.pay_time);
  224. }
  225. return await this.update(payload, {
  226. id,
  227. });
  228. }
  229. /**
  230. * 删除预付款记录
  231. * @param {String} id 预付款id
  232. * @param {String} tid 标段id
  233. */
  234. async deleteAdvance(id, tid) {
  235. const transaction = await this.db.beginTransaction();
  236. try {
  237. // 删除预付款记录
  238. await transaction.delete(this.tableName, { id, tid });
  239. // 删除附件
  240. const fileInfo = await this.db.select(this.ctx.service.advanceFile.tableName, { where: { vid: id, tid } });
  241. await transaction.delete(this.ctx.service.advanceFile.tableName, { vid: id, tid });
  242. await this.ctx.helper.delFiles(fileInfo);
  243. // 先删除文件
  244. // for (let i = 0; i < fileInfo.length; i++) {
  245. // const file = fileInfo[i];
  246. // if (fs.existsSync(path.resolve(this.app.baseDir, './app', file.filepath))) {
  247. // fs.unlinkSync(path.resolve(this.app.baseDir, './app', file.filepath));
  248. // // fs.unlinkSync(path.resolve(this.app.baseDir, zipPath));
  249. // }
  250. // await this.ctx.app.fujianOss.delete(file.filepath);
  251. // }
  252. // 删除审批记录
  253. await transaction.delete(this.ctx.service.advanceAudit.tableName, { vid: id, tid });
  254. await transaction.commit();
  255. } catch (err) {
  256. await transaction.rollback();
  257. throw err;
  258. }
  259. }
  260. async getListByArchives(tid, ids) {
  261. if (ids.length === 0) return [];
  262. const sql = 'SELECT c.* FROM ?? as c LEFT JOIN (SELECT vid, MAX(end_time) as end_time FROM ?? WHERE ' +
  263. 'tid = ? AND vid in (' + this.ctx.helper.getInArrStrSqlFilter(ids) + ') GROUP BY vid) as ca ON c.id = ca.vid WHERE' +
  264. ' c.tid = ? AND c.id in (' + this.ctx.helper.getInArrStrSqlFilter(ids) + ') AND c.status = ? ORDER BY ca.end_time DESC';
  265. const params = [this.tableName, this.ctx.service.advanceAudit.tableName, tid, tid, auditConst.status.checked];
  266. const list = await this.db.query(sql, params);
  267. // 再按预付款顺序再进行一次排列
  268. const advances = [];
  269. for (const tc of advanceConst.typeCol) {
  270. const typeList = list.filter(item => item.type === tc.type);
  271. advances.push(...typeList);
  272. }
  273. return advances;
  274. }
  275. }
  276. return Advance;
  277. };