advance.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. * 获取预付款最新一期
  68. * @param {Number} tid 标段id
  69. * @param {String} type 类型: 开工预付款|材料预付款 (0|1)
  70. * @param {Boolean} includeUnCheck 包括未上报的
  71. * @return {Promise<*>} 实例结果集
  72. */
  73. async getLastestAdvance(tid, type, includeUnCheck = false) {
  74. this.initSqlBuilder();
  75. this.sqlBuilder.setAndWhere('tid', {
  76. value: tid,
  77. operate: '=',
  78. });
  79. this.sqlBuilder.setAndWhere('type', {
  80. value: type,
  81. operate: '=',
  82. });
  83. if (!includeUnCheck) {
  84. this.sqlBuilder.setAndWhere('status', {
  85. value: auditConst.status.uncheck,
  86. operate: '!=',
  87. });
  88. }
  89. this.sqlBuilder.orderBy = [['order', 'desc']];
  90. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  91. const advance = await this.db.queryOne(sql, sqlParam);
  92. return advance;
  93. }
  94. async getSumAdvance(tid) {
  95. const sql = 'Select sum(cur_amount) as tp From ' + this.tableName + ' where tid = ?';
  96. const result = await this.db.queryOne(sql, [tid]);
  97. return result ? result.tp : 0;
  98. }
  99. /**
  100. * 创建一条新的记录
  101. * @param {String} type 类型: 开工预付款|材料预付款 (start|material)
  102. * @return {Promise<*>} 插入结果集
  103. */
  104. async createRecord(type) {
  105. const { ctx } = this;
  106. const uid = ctx.session.sessionUser.accountId;
  107. const tid = ctx.tender.id;
  108. let latestOrder = await this.getLastestAdvance(tid, type, true);
  109. if (latestOrder && latestOrder.status === auditConst.status.uncheck) {
  110. return '';
  111. }
  112. if (!latestOrder) {
  113. latestOrder = {
  114. order: 1,
  115. prev_amount: 0,
  116. prev_total_amount: 0,
  117. };
  118. } else {
  119. latestOrder.order = latestOrder.order + 1;
  120. }
  121. 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 });
  122. const auditors = await ctx.service.advanceAudit.getAuditGroupByList(latestOrder.id, latestOrder.times);
  123. for (let idx = 0; idx < auditors.length; idx++) {
  124. const { audit_id } = auditors[idx];
  125. await ctx.service.advanceAudit.db.insert(ctx.service.advanceAudit.tableName, {
  126. tid: latestOrder.tid, audit_id, type: latestOrder.type, vid: record.insertId, times: 1, order: idx + 1, status: 1, create_time: new Date(),
  127. });
  128. }
  129. // auditors.forEach(async (auditor, idx) => {
  130. // const { audit_id } = auditor;
  131. // await ctx.service.advanceAudit.db.insert(ctx.service.advanceAudit.tableName, {
  132. // tid: latestOrder.tid, audit_id, type: latestOrder.type, vid: record.insertId, times: 1, order: idx + 1, status: 1, create_time: new Date(),
  133. // });
  134. // });
  135. return await this.getDataById(record.insertId);
  136. }
  137. /**
  138. * 获取上一期预付款记录
  139. * @param {Number} tid 标段id
  140. * @param {Number} type 预付款类型
  141. */
  142. async getPreviousRecord(tid, type) {
  143. this.initSqlBuilder();
  144. this.sqlBuilder.setAndWhere('tid', {
  145. value: tid,
  146. operate: '=',
  147. });
  148. this.sqlBuilder.setAndWhere('type', {
  149. value: type,
  150. operate: '=',
  151. });
  152. this.sqlBuilder.setAndWhere('order', {
  153. value: this.ctx.advance.order - 1,
  154. operate: '=',
  155. });
  156. this.sqlBuilder.orderBy = [['order', 'desc']];
  157. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  158. return await this.db.queryOne(sql, sqlParam);
  159. }
  160. /**
  161. * 计算列表进度条所需数据
  162. * @param {Object} latest 最新期的数据
  163. * @param {Number} payTotal 预付款金额总数
  164. * @return {Object} progress所需数据
  165. */
  166. async calcProgress(latest, payTotal) {
  167. const { ctx } = this;
  168. if (!latest) {
  169. latest = { prev_total_amount: 0, prev_amount: 0, cur_amount: 0 };
  170. }
  171. const surplus = ctx.helper.sub(payTotal, latest.prev_total_amount || 0);
  172. const p_ratio = ctx.helper.mul(ctx.helper.div(latest.prev_amount || 0, payTotal), 100, 2); // 截止上期金额总数
  173. const c_ratio = ctx.helper.mul(ctx.helper.div(latest.cur_amount || 0, payTotal), 100, 2); // 截止本期金额总数
  174. const s_ratio = ctx.helper.mul(ctx.helper.div(surplus, payTotal), 100, 2); // 剩余金额总数
  175. return {
  176. p_amount: latest.prev_amount,
  177. c_amount: latest.cur_amount,
  178. s_amount: surplus,
  179. p_ratio,
  180. c_ratio,
  181. s_ratio,
  182. };
  183. }
  184. /**
  185. * 更新预付款记录
  186. * @param {Object} payload 载荷
  187. * @param {Number} id 预付款id
  188. */
  189. async updateAdvance(payload, id) {
  190. const { ctx } = this;
  191. const prevRecord = await this.getPreviousRecord(ctx.tender.id, ctx.advance.type) || { prev_total_amount: 0 };
  192. const { cur_amount } = payload;
  193. payload.prev_total_amount = ctx.helper.add(cur_amount, prevRecord.prev_total_amount);
  194. return await this.update(payload, {
  195. id,
  196. });
  197. }
  198. /**
  199. * 删除预付款记录
  200. * @param {String} id 预付款id
  201. * @param {String} tid 标段id
  202. */
  203. async deleteAdvance(id, tid) {
  204. const transaction = await this.db.beginTransaction();
  205. try {
  206. // 删除预付款记录
  207. await transaction.delete(this.tableName, { id, tid });
  208. // 删除附件
  209. const fileInfo = await this.db.select(this.ctx.service.advanceFile.tableName, { where: { vid: id, tid } });
  210. await transaction.delete(this.ctx.service.advanceFile.tableName, { vid: id, tid });
  211. await this.ctx.helper.delFiles(fileInfo);
  212. // 先删除文件
  213. // for (let i = 0; i < fileInfo.length; i++) {
  214. // const file = fileInfo[i];
  215. // if (fs.existsSync(path.resolve(this.app.baseDir, './app', file.filepath))) {
  216. // fs.unlinkSync(path.resolve(this.app.baseDir, './app', file.filepath));
  217. // // fs.unlinkSync(path.resolve(this.app.baseDir, zipPath));
  218. // }
  219. // await this.ctx.app.fujianOss.delete(file.filepath);
  220. // }
  221. // 删除审批记录
  222. await transaction.delete(this.ctx.service.advanceAudit.tableName, { vid: id, tid });
  223. await transaction.commit();
  224. } catch (err) {
  225. await transaction.rollback();
  226. throw err;
  227. }
  228. }
  229. }
  230. return Advance;
  231. };