payment_detail.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. 'use strict';
  2. const auditConst = require('../const/audit').stage;
  3. const paymentConst = require('../const/payment');
  4. module.exports = app => {
  5. class PaymentDetail extends app.BaseService {
  6. constructor(ctx) {
  7. super(ctx);
  8. this.tableName = 'payment_detail';
  9. }
  10. async getValidDetails(tr_id) {
  11. const details = await this.db.select(this.tableName, {
  12. column: ['id', 'in_time', 'tr_id', 'uid', 'status', 'order', 'times', 'code', 's_time'],
  13. where: { tr_id },
  14. orders: [['order', 'desc']],
  15. });
  16. if (details.length !== 0) {
  17. const lastDetail = details[details.length - 1];
  18. if (lastDetail.status === auditConst.status.uncheck && lastDetail.uid !== this.ctx.session.sessionUser.accountId) {
  19. details.splice(details.length - 1, 1);
  20. }
  21. }
  22. // 最新一期计量(未审批完成),当前操作人的期详细数据,应实时计算
  23. if (details.length > 0 && details[0].status !== auditConst.status.checked) {
  24. const detail = details[0];
  25. const curAuditor = await this.ctx.service.paymentDetailAudit.getCurAuditor(detail.id, detail.times);
  26. const isActive = curAuditor ? curAuditor.id === this.ctx.session.sessionUser.accountId : detail.uid === this.ctx.session.sessionUser.accountId;
  27. if (isActive) {
  28. detail.curTimes = detail.times;
  29. detail.curOrder = curAuditor ? curAuditor.order : 0;
  30. }
  31. }
  32. return details;
  33. }
  34. async hadDetail(trId) {
  35. const result = await this.count({ tr_id: trId });
  36. return result !== 0;
  37. }
  38. async addCommomCheck(trInfo, code) {
  39. const details = await this.getAllDataByCondition({
  40. where: { tr_id: trInfo.id },
  41. order: ['order'],
  42. });
  43. const preDetail = details[details.length - 1];
  44. if (details.length > 0 && details[details.length - 1].status !== auditConst.status.checked) {
  45. throw '上一期未审批通过,请等待上一期审批通过后,再新增';
  46. }
  47. if (this._.findIndex(details, { code }) !== -1) {
  48. throw '编号不能重复';
  49. }
  50. trInfo.rpt_audit = JSON.parse(trInfo.rpt_audit);
  51. if (this._.findIndex(trInfo.rpt_audit, { uid: null }) !== -1) {
  52. throw '未配置好表单角色,无法新建';
  53. }
  54. return preDetail;
  55. }
  56. async addFormDetail(trInfo, code, s_time) {
  57. const transaction = await this.db.beginTransaction();
  58. try {
  59. if (!(trInfo.is_del === 0 && trInfo.rpt_audit)) {
  60. throw '报表已删除或表单人员数据有误,无法新建';
  61. }
  62. const preDetail = await this.addCommomCheck(trInfo, code);
  63. const rptTpl = await this.ctx.service.rptTpl.getDataById(trInfo.rpt_id);
  64. const pageRst = this.ctx.service.jpcReport.getAllPreviewPagesCommon(rptTpl, 'A4');
  65. const newDetail = {
  66. tender_id: this.ctx.paymentTender.id,
  67. tr_id: trInfo.id,
  68. order: preDetail.order ? preDetail.order + 1 : 1,
  69. times: 1,
  70. status: auditConst.status.uncheck,
  71. uid: this.ctx.session.sessionUser.accountId,
  72. s_time,
  73. code,
  74. report_json: JSON.stringify(pageRst),
  75. in_time: new Date(),
  76. };
  77. const result = await transaction.insert(this.tableName, newDetail);
  78. if (result.affectedRows === 1) {
  79. newDetail.id = result.insertId;
  80. } else {
  81. throw '新增支付审批数据失败';
  82. }
  83. // 报表角色创建
  84. const insertRptAudit = [];
  85. for (const [i, r] of trInfo.rpt_audit.entries()) {
  86. insertRptAudit.push({
  87. tender_id: this.ctx.paymentTender.id,
  88. tr_id: trInfo.id,
  89. td_id: newDetail.id,
  90. uid: r.uid,
  91. signature_index: i,
  92. signature_name: r.rpt_name,
  93. in_time: new Date(),
  94. });
  95. }
  96. if (insertRptAudit.length > 0) await transaction.insert(this.ctx.service.paymentRptAudit.tableName, insertRptAudit);
  97. // 存在上一期时,复制上一期审批流程
  98. if (preDetail) {
  99. const auditResult = await this.ctx.service.paymentDetailAudit.copyPreDetailAuditors(transaction, preDetail, newDetail);
  100. if (!auditResult) {
  101. throw '复制上一期审批流程失败';
  102. }
  103. }
  104. // 更新is_change值
  105. await transaction.update(this.ctx.service.paymentTenderRpt.tableName, { id: trInfo.id, is_change: 0 });
  106. await transaction.commit();
  107. return newDetail;
  108. } catch (err) {
  109. await transaction.rollback();
  110. throw err;
  111. }
  112. }
  113. async addSafeDetail(trInfo, code, s_time) {
  114. const transaction = await this.db.beginTransaction();
  115. try {
  116. const preDetail = await this.addCommomCheck(trInfo, code);
  117. const newDetail = {
  118. tender_id: this.ctx.paymentTender.id,
  119. tr_id: trInfo.id,
  120. order: preDetail && preDetail.order ? preDetail.order + 1 : 1,
  121. times: 1,
  122. status: auditConst.status.uncheck,
  123. uid: this.ctx.session.sessionUser.accountId,
  124. s_time,
  125. code,
  126. in_time: new Date(),
  127. type: paymentConst.modes_value_object.safe,
  128. };
  129. const result = await transaction.insert(this.tableName, newDetail);
  130. if (result.affectedRows === 1) {
  131. newDetail.id = result.insertId;
  132. } else {
  133. throw '新增支付审批数据失败';
  134. }
  135. // 初始化安全生产费
  136. await this.ctx.service.paymentSafeBills.init(newDetail, transaction);
  137. // 存在上一期时,复制上一期审批流程
  138. if (preDetail) {
  139. const auditResult = await this.ctx.service.paymentDetailAudit.copyPreDetailAuditors(transaction, preDetail, newDetail);
  140. if (!auditResult) {
  141. throw '复制上一期审批流程失败';
  142. }
  143. }
  144. // 更新is_change值
  145. await transaction.update(this.ctx.service.paymentTenderRpt.tableName, { id: trInfo.id, is_change: 0 });
  146. await transaction.commit();
  147. return newDetail;
  148. } catch (err) {
  149. await transaction.rollback();
  150. throw err;
  151. }
  152. }
  153. async addDetail(trInfo, code, s_time) {
  154. switch (trInfo.type) {
  155. case paymentConst.modes_value_object.form:
  156. this.addFormDetail(trInfo, code, s_time);
  157. break;
  158. case paymentConst.modes_value_object.safe:
  159. this.addSafeDetail(trInfo, code, s_time);
  160. break;
  161. default:
  162. throw '未知类型,新建失败';
  163. }
  164. }
  165. async updateReportJson(id, report_json) {
  166. return await this.db.update(this.tableName, { id, report_json: JSON.stringify(report_json) });
  167. }
  168. async signOneSignatureData(report_json, signature_name, sign_msg) {
  169. // 签名签章
  170. const signCells = this._.find(report_json.items[0].signature_cells, { signature_name });
  171. if (signCells && (sign_msg.sign_path || sign_msg.company_stamp || sign_msg.stamp_path)) {
  172. const signArray = [];
  173. sign_msg.sign_path ? signArray.push('/public/upload/sign/' + sign_msg.sign_path) : signArray.push('');
  174. sign_msg.company_stamp ? signArray.push(sign_msg.company_stamp) : signArray.push('');
  175. sign_msg.stamp_path ? signArray.push(sign_msg.stamp_path) : signArray.push('');
  176. signCells.path = signArray.join('!;!');
  177. }
  178. // 日期
  179. const dateCells = this._.find(report_json.items[0].signature_date_cells, { signature_name: signature_name + '_签字日期' });
  180. if (dateCells && sign_msg.date) {
  181. dateCells.Value = this.ctx.helper.dateTranChinese(sign_msg.date);
  182. }
  183. // 意见
  184. const contentCells = this._.find(report_json.items[0].signature_audit_cells, { signature_name: signature_name + '_审核意见' });
  185. if (contentCells && sign_msg.content) {
  186. contentCells.Value = sign_msg.content;
  187. }
  188. return report_json;
  189. }
  190. async clearOneSignatureData(report_json, rptAudit) {
  191. // 签名签章
  192. const signCells = this._.find(report_json.items[0].signature_cells, { signature_name: rptAudit.signature_name });
  193. if (signCells) {
  194. signCells.path = null;
  195. }
  196. // 日期
  197. const dateCells = this._.find(report_json.items[0].signature_date_cells, { signature_name: rptAudit.signature_name + '_签字日期' });
  198. if (dateCells) {
  199. dateCells.Value = '';
  200. }
  201. // 意见
  202. const contentCells = this._.find(report_json.items[0].signature_audit_cells, { signature_name: rptAudit.signature_name + '_审核意见' });
  203. if (contentCells) {
  204. contentCells.Value = '';
  205. }
  206. return report_json;
  207. }
  208. async clearAllSignatureData(report_json) {
  209. if (report_json.items[0].signature_cells.length > 0) {
  210. for (const cell of report_json.items[0].signature_cells) {
  211. cell.path = null;
  212. }
  213. }
  214. if (report_json.items[0].signature_audit_cells.length > 0) {
  215. for (const cell of report_json.items[0].signature_audit_cells) {
  216. cell.Value = '';
  217. }
  218. }
  219. if (report_json.items[0].signature_date_cells.length > 0) {
  220. for (const cell of report_json.items[0].signature_date_cells) {
  221. cell.Value = '';
  222. }
  223. }
  224. return report_json;
  225. }
  226. /**
  227. * 删除报表表单详情
  228. *
  229. * @param {Number} id - 期Id
  230. * @return {Promise<void>}
  231. */
  232. async deleteDetail(id) {
  233. const transaction = await this.db.beginTransaction();
  234. try {
  235. await transaction.delete(this.ctx.service.paymentDetailAudit.tableName, { td_id: id });
  236. await transaction.delete(this.ctx.service.paymentRptAudit.tableName, { td_id: id });
  237. await transaction.delete(this.tableName, { id });
  238. await transaction.commit();
  239. return true;
  240. } catch (err) {
  241. await transaction.rollback();
  242. throw err;
  243. }
  244. }
  245. async haveNotice2Tender(tid, uid) {
  246. const sql = 'SELECT pd.`id`, pd.`tr_id`, pd.`order` FROM ?? as pd LEFT JOIN ?? as pda' +
  247. ' ON pd.`id` = pda.`td_id` LEFT JOIN ?? as pra ON pd.`id` = pra.`td_id` WHERE pd.`tender_id` = ? AND' +
  248. ' ((pd.`uid` = ? AND (pd.`status` = ? OR pd.`status` = ?))' +
  249. ' OR ((pd.`status` = ? OR pd.`status` = ?) AND pda.aid = ? AND pda.`status` = ?)' +
  250. ' OR (pra.`uid` = ? AND pra.`signature_msg` is null AND pd.`status` != ? AND pd.`status` != ?))';
  251. const params = [this.tableName, this.ctx.service.paymentDetailAudit.tableName, this.ctx.service.paymentRptAudit.tableName, tid,
  252. uid, auditConst.status.uncheck, auditConst.status.checkNo,
  253. auditConst.status.checking, auditConst.status.checkNoPre, uid, auditConst.status.checking,
  254. uid, auditConst.status.uncheck, auditConst.status.checkNo];
  255. const result = await this.db.query(sql, params);
  256. if (result && result.length > 0) {
  257. for (const one of this._.uniqBy(result, 'id')) {
  258. const maxOrder = await this.count({
  259. tr_id: one.tr_id,
  260. });
  261. if (one.order === maxOrder) {
  262. return 1;
  263. }
  264. }
  265. }
  266. return 0;
  267. }
  268. async haveNotice2TenderRpt(tr_id, uid) {
  269. const sql = 'SELECT pd.`id`, pd.`tr_id`, pd.`order` FROM ?? as pd LEFT JOIN ?? as pda' +
  270. ' ON pd.`id` = pda.`td_id` LEFT JOIN ?? as pra ON pd.`id` = pra.`td_id` WHERE pd.`tr_id` = ? AND ((pd.`uid` = ? AND (pd.`status` = ? OR pd.`status` = ?))' +
  271. ' OR ((pd.`status` = ? OR pd.`status` = ?) AND pda.aid = ? AND pda.`status` = ?)' +
  272. ' OR (pra.`uid` = ? AND pra.`signature_msg` is null AND pd.`status` != ? AND pd.`status` != ?))';
  273. const params = [this.tableName, this.ctx.service.paymentDetailAudit.tableName, this.ctx.service.paymentRptAudit.tableName, tr_id,
  274. uid, auditConst.status.uncheck, auditConst.status.checkNo,
  275. auditConst.status.checking, auditConst.status.checkNoPre, uid, auditConst.status.checking,
  276. uid, auditConst.status.uncheck, auditConst.status.checkNo];
  277. const result = await this.db.query(sql, params);
  278. if (result && result.length > 0) {
  279. for (const one of this._.uniqBy(result, 'id')) {
  280. const maxOrder = await this.count({
  281. tr_id: one.tr_id,
  282. });
  283. if (one.order === maxOrder) {
  284. return 1;
  285. }
  286. }
  287. }
  288. return 0;
  289. }
  290. async haveDetail2Tender(tid) {
  291. return this.count({ tender_id: tid });
  292. }
  293. async getCountByPidType(pid, type = 1) {
  294. const sql = 'SELECT count(pd.`id`) as count FROM ?? as pd LEFT JOIN ?? as pt ON pd.`tender_id` = pt.`id` WHERE pid = ? AND type = ?';
  295. const params = [this.tableName, this.ctx.service.paymentTender.tableName, pid, type];
  296. const result = await this.db.queryOne(sql, params);
  297. return result ? result.count : 0;
  298. }
  299. async updateReport(transaction, tr_id, uid) {
  300. const details = await this.db.select(this.tableName, {
  301. column: ['id', 'in_time', 'tr_id', 'uid', 'status', 'order', 'times', 'code', 's_time'],
  302. where: { tr_id },
  303. orders: [['order', 'desc']],
  304. });
  305. if (details && details.length > 0) {
  306. const detailInfo = details[0];
  307. if (detailInfo.status === auditConst.status.uncheck || detailInfo.status === auditConst.status.checkNo) {
  308. // 判断该人是否在审批流程里,是则移除并调整order
  309. const result2 = await this.ctx.service.paymentDetailAudit.updateAuditByReport(transaction, detailInfo.id, detailInfo.times, uid);
  310. // 更新为上报人
  311. return await transaction.update(this.tableName, { id: detailInfo.id, uid });
  312. }
  313. }
  314. return true;
  315. }
  316. }
  317. return PaymentDetail;
  318. };