advance.js 12 KB

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