'use strict'; const auditConst = require('../const/audit').stage; const paymentConst = require('../const/payment'); module.exports = app => { class PaymentDetail extends app.BaseService { constructor(ctx) { super(ctx); this.tableName = 'payment_detail'; } async getValidDetails(tr_id) { const details = await this.db.select(this.tableName, { column: ['id', 'in_time', 'tr_id', 'uid', 'status', 'order', 'times', 'code', 's_time', 'bills_decimal'], where: { tr_id }, orders: [['order', 'desc']], }); if (details.length !== 0) { const lastDetail = details[details.length - 1]; if (lastDetail.status === auditConst.status.uncheck && lastDetail.uid !== this.ctx.session.sessionUser.accountId) { details.splice(details.length - 1, 1); } } // 最新一期计量(未审批完成),当前操作人的期详细数据,应实时计算 if (details.length > 0 && details[0].status !== auditConst.status.checked) { const detail = details[0]; const curAuditor = await this.ctx.service.paymentDetailAudit.getCurAuditor(detail.id, detail.times); const isActive = curAuditor ? curAuditor.aid === this.ctx.session.sessionUser.accountId : detail.uid === this.ctx.session.sessionUser.accountId; if (isActive) { detail.curTimes = detail.times; detail.curOrder = curAuditor ? curAuditor.order : 0; } } return details; } async getDetail(id) { const details = await this.db.select(this.tableName, { column: ['id', 'in_time', 'tr_id', 'uid', 'status', 'order', 'times', 'code', 's_time', 'bills_decimal'], where: { id }, orders: [['order', 'desc']], }); return details; } async hadDetail(trId) { const result = await this.count({ tr_id: trId }); return result !== 0; } async addCommomCheck(trInfo, code) { const details = await this.getAllDataByCondition({ where: { tr_id: trInfo.id }, order: ['order'], }); const preDetail = details[details.length - 1]; if (details.length > 0 && details[details.length - 1].status !== auditConst.status.checked) { throw '上一期未审批通过,请等待上一期审批通过后,再新增'; } if (this._.findIndex(details, { code }) !== -1) { throw '编号不能重复'; } trInfo.rpt_audit = JSON.parse(trInfo.rpt_audit); if (this._.findIndex(trInfo.rpt_audit, { uid: null }) !== -1) { throw '未配置好表单角色,无法新建'; } return preDetail; } // async addFormDetail(trInfo, code, s_time) { async addFormDetail(trInfo, code, s_time) { const transaction = await this.db.beginTransaction(); try { if (!(trInfo.is_del === 0 && trInfo.rpt_audit)) { throw '报表已删除或表单人员数据有误,无法新建'; } const preDetail = await this.addCommomCheck(trInfo, code); const rptTpl = await this.ctx.service.rptTpl.getDataById(trInfo.rpt_id); const pageRst = await this.ctx.service.jpcReport.getAllPreviewPagesCommon(rptTpl, 'A4'); const newDetail = { tender_id: this.ctx.paymentTender.id, tr_id: trInfo.id, order: preDetail && preDetail.order ? preDetail.order + 1 : 1, times: 1, status: auditConst.status.uncheck, uid: this.ctx.session.sessionUser.accountId, s_time, code, report_json: JSON.stringify(pageRst), in_time: new Date(), }; newDetail.bills_decimal = preDetail ? preDetail.bills_decimal : JSON.stringify(this.ctx.service.paymentSafeBills.decimal); const result = await transaction.insert(this.tableName, newDetail); if (result.affectedRows === 1) { newDetail.id = result.insertId; } else { throw '新增支付审批数据失败'; } // 报表角色创建 const insertRptAudit = []; for (const [i, r] of trInfo.rpt_audit.entries()) { insertRptAudit.push({ tender_id: this.ctx.paymentTender.id, tr_id: trInfo.id, td_id: newDetail.id, uid: r.uid, signature_index: i, signature_name: r.rpt_name, in_time: new Date(), }); } if (insertRptAudit.length > 0) await transaction.insert(this.ctx.service.paymentRptAudit.tableName, insertRptAudit); // 存在上一期时,复制上一期审批流程 if (preDetail) { const auditResult = await this.ctx.service.paymentDetailAudit.copyPreDetailAuditors(transaction, preDetail, newDetail); if (!auditResult) { throw '复制上一期审批流程失败'; } } // 更新is_change值 await transaction.update(this.ctx.service.paymentTenderRpt.tableName, { id: trInfo.id, is_change: 0 }); await transaction.commit(); return newDetail; } catch (err) { await transaction.rollback(); throw err; } } async addSafeDetail(trInfo, code, s_time) { const transaction = await this.db.beginTransaction(); try { const preDetail = await this.addCommomCheck(trInfo, code); const newDetail = { tender_id: this.ctx.paymentTender.id, tr_id: trInfo.id, order: preDetail && preDetail.order ? preDetail.order + 1 : 1, times: 1, status: auditConst.status.uncheck, uid: this.ctx.session.sessionUser.accountId, s_time, code, in_time: new Date(), type: paymentConst.modes_value_object.safe, }; newDetail.bills_decimal = preDetail ? preDetail.bills_decimal : JSON.stringify(this.ctx.service.paymentSafeBills.decimal); const result = await transaction.insert(this.tableName, newDetail); if (result.affectedRows === 1) { newDetail.id = result.insertId; } else { throw '新增支付审批数据失败'; } // 初始化安全生产费 if (preDetail) { await this.ctx.service.paymentSafeBills.initByPre(newDetail, preDetail, transaction); } else { await this.ctx.service.paymentSafeBills.init(newDetail, transaction); } // 存在上一期时,复制上一期审批流程 if (preDetail) { const auditResult = await this.ctx.service.paymentDetailAudit.copyPreDetailAuditors(transaction, preDetail, newDetail); if (!auditResult) { throw '复制上一期审批流程失败'; } } // 更新is_change值 await transaction.update(this.ctx.service.paymentTenderRpt.tableName, { id: trInfo.id, is_change: 0 }); await transaction.commit(); return newDetail; } catch (err) { await transaction.rollback(); throw err; } } async addDetail(trInfo, code, s_time) { switch (trInfo.type) { case paymentConst.modes_value_object.form: return this.addFormDetail(trInfo, code, s_time); case paymentConst.modes_value_object.safe: return this.addSafeDetail(trInfo, code, s_time); default: throw '未知类型,新建失败'; } } async updateReportJson(id, report_json) { return await this.db.update(this.tableName, { id, report_json: JSON.stringify(report_json) }); } async signOneSignatureData(report_json, signature_name, sign_msg) { // 签名签章 const signCells = this._.find(report_json.items[0].signature_cells, { signature_name }); if (signCells && (sign_msg.sign_path || sign_msg.company_stamp || sign_msg.stamp_path)) { const signArray = []; sign_msg.sign_path ? signArray.push('/public/upload/sign/' + sign_msg.sign_path) : signArray.push(''); sign_msg.company_stamp ? signArray.push(sign_msg.company_stamp) : signArray.push(''); sign_msg.stamp_path ? signArray.push(sign_msg.stamp_path) : signArray.push(''); signCells.path = signArray.join('!;!'); } // 日期 const dateCells = this._.find(report_json.items[0].signature_date_cells, { signature_name: signature_name + '_签字日期' }); if (dateCells && sign_msg.date) { dateCells.Value = this.ctx.helper.dateTranChinese(sign_msg.date); } // 意见 const contentCells = this._.find(report_json.items[0].signature_audit_cells, { signature_name: signature_name + '_审核意见' }); if (contentCells && sign_msg.content) { contentCells.Value = sign_msg.content; } return report_json; } async clearOneSignatureData(report_json, rptAudit) { // 签名签章 const signCells = this._.find(report_json.items[0].signature_cells, { signature_name: rptAudit.signature_name }); if (signCells) { signCells.path = null; } // 日期 const dateCells = this._.find(report_json.items[0].signature_date_cells, { signature_name: rptAudit.signature_name + '_签字日期' }); if (dateCells) { dateCells.Value = ''; } // 意见 const contentCells = this._.find(report_json.items[0].signature_audit_cells, { signature_name: rptAudit.signature_name + '_审核意见' }); if (contentCells) { contentCells.Value = ''; } return report_json; } async clearAllSignatureData(report_json) { if (report_json.items[0].signature_cells.length > 0) { for (const cell of report_json.items[0].signature_cells) { cell.path = null; } } if (report_json.items[0].signature_audit_cells.length > 0) { for (const cell of report_json.items[0].signature_audit_cells) { cell.Value = ''; } } if (report_json.items[0].signature_date_cells.length > 0) { for (const cell of report_json.items[0].signature_date_cells) { cell.Value = ''; } } return report_json; } /** * 删除报表表单详情 * * @param {Number} id - 期Id * @return {Promise} */ async deleteDetail(id) { const transaction = await this.db.beginTransaction(); try { await transaction.delete(this.ctx.service.paymentDetailAudit.tableName, { td_id: id }); await transaction.delete(this.ctx.service.paymentRptAudit.tableName, { td_id: id }); await transaction.delete(this.ctx.service.paymentSafeBills.tableName, { detail_id: id }); await transaction.delete(this.tableName, { id }); await transaction.commit(); return true; } catch (err) { await transaction.rollback(); throw err; } } async haveNotice2Tender(tid, uid) { const sql = 'SELECT pd.`id`, pd.`tr_id`, pd.`order` FROM ?? as pd LEFT JOIN ?? as pda' + ' ON pd.`id` = pda.`td_id` LEFT JOIN ?? as pra ON pd.`id` = pra.`td_id` WHERE pd.`tender_id` = ? AND' + ' ((pd.`uid` = ? AND (pd.`status` = ? OR pd.`status` = ?))' + ' OR ((pd.`status` = ? OR pd.`status` = ?) AND pda.aid = ? AND pda.`status` = ?)' + ' OR (pra.`uid` = ? AND pra.`signature_msg` is null AND pd.`status` != ? AND pd.`status` != ?))'; const params = [this.tableName, this.ctx.service.paymentDetailAudit.tableName, this.ctx.service.paymentRptAudit.tableName, tid, uid, auditConst.status.uncheck, auditConst.status.checkNo, auditConst.status.checking, auditConst.status.checkNoPre, uid, auditConst.status.checking, uid, auditConst.status.uncheck, auditConst.status.checkNo]; const result = await this.db.query(sql, params); if (result && result.length > 0) { for (const one of this._.uniqBy(result, 'id')) { const maxOrder = await this.count({ tr_id: one.tr_id, }); if (one.order === maxOrder) { return 1; } } } return 0; } async haveNotice2TenderRpt(tr_id, uid) { const sql = 'SELECT pd.`id`, pd.`tr_id`, pd.`order` FROM ?? as pd LEFT JOIN ?? as pda' + ' 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` = ?))' + ' OR ((pd.`status` = ? OR pd.`status` = ?) AND pda.aid = ? AND pda.`status` = ?)' + ' OR (pra.`uid` = ? AND pra.`signature_msg` is null AND pd.`status` != ? AND pd.`status` != ?))'; const params = [this.tableName, this.ctx.service.paymentDetailAudit.tableName, this.ctx.service.paymentRptAudit.tableName, tr_id, uid, auditConst.status.uncheck, auditConst.status.checkNo, auditConst.status.checking, auditConst.status.checkNoPre, uid, auditConst.status.checking, uid, auditConst.status.uncheck, auditConst.status.checkNo]; const result = await this.db.query(sql, params); if (result && result.length > 0) { for (const one of this._.uniqBy(result, 'id')) { const maxOrder = await this.count({ tr_id: one.tr_id, }); if (one.order === maxOrder) { return 1; } } } return 0; } async haveDetail2Tender(tid) { return this.count({ tender_id: tid }); } async getCountByPidType(pid, type = 1) { 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 = ?'; const params = [this.tableName, this.ctx.service.paymentTender.tableName, pid, type]; const result = await this.db.queryOne(sql, params); return result ? result.count : 0; } async updateReport(transaction, tr_id, uid) { const details = await this.db.select(this.tableName, { column: ['id', 'in_time', 'tr_id', 'uid', 'status', 'order', 'times', 'code', 's_time'], where: { tr_id }, orders: [['order', 'desc']], }); if (details && details.length > 0) { const detailInfo = details[0]; if (detailInfo.status === auditConst.status.uncheck || detailInfo.status === auditConst.status.checkNo) { // 判断该人是否在审批流程里,是则移除并调整order const result2 = await this.ctx.service.paymentDetailAudit.updateAuditByReport(transaction, detailInfo.id, detailInfo.times, uid); // 更新为上报人 return await transaction.update(this.tableName, { id: detailInfo.id, uid }); } } return true; } async doCheckDetail(id) { const status = auditConst.status; const accountId = this.ctx.session.sessionUser.accountId; const auditPermission = await this.ctx.service.subProjPermission.getPaymentPermission(this.ctx.subProject.permission.payment_permission); if (!auditPermission) throw '权限不足'; const detail = await this.getDataById(id); if (!detail) throw '支付审批表单不存在'; const trInfo = await this.ctx.service.paymentTenderRpt.getDataById(detail.tr_id); if (!trInfo) throw '支付审批报表不存在'; // 读取原报、审核人数据 detail.auditors = await this.ctx.service.paymentDetailAudit.getAuditors(detail.id, detail.times); detail.curAuditor = await this.ctx.service.paymentDetailAudit.getCurAuditor(detail.id, detail.times); detail.rptAudits = await this.ctx.service.paymentRptAudit.getListByDetail(detail.id); const auditorIds = this._.map(detail.auditors, 'aid'), rptAuditIds = this._.map(detail.rptAudits, 'uid'); if (accountId === detail.uid) { // 原报 detail.curTimes = detail.times; if (detail.status === status.uncheck || detail.status === status.checkNo) { detail.curOrder = 0; } else if (detail.status === status.checked) { detail.curOrder = this._.max(this._.map(detail.auditors, 'order')); } else { detail.curOrder = detail.curAuditor.aid === accountId ? detail.curAuditor.order : detail.curAuditor.order - 1; } detail.filePermission = true; } else if (auditorIds.indexOf(accountId) !== -1 || rptAuditIds.indexOf(accountId) !== -1 || auditPermission.view_all) { // 审批人及签署人及查看所有权人 if (detail.status === status.uncheck) { throw '您无权查看该数据'; } detail.curTimes = detail.status === status.checkNo ? detail.times - 1 : detail.times; if (detail.status === status.checked) { detail.curOrder = this._.max(this._.map(detail.auditors, 'order')); } else if (detail.status === status.checkNo) { const audit = await this.ctx.service.paymentDetailAudit.getDataByCondition({ td_id: detail.id, times: detail.times, status: status.checkNo, }); detail.curOrder = audit.order; } else { detail.curOrder = accountId === detail.curAuditor.aid ? detail.curAuditor.order : detail.curAuditor.order - 1; } detail.filePermission = auditorIds.indexOf(accountId) !== -1 || rptAuditIds.indexOf(accountId) !== -1; } else { // 其他不可见 throw '您无权查看该数据'; } // 获取最新的期 detail.highOrder = await this.service.paymentDetail.count({ tr_id: detail.tr_id }); detail.readOnly = !((detail.status === status.uncheck || detail.status === status.checkNo) && accountId === detail.uid); if (detail.readOnly && detail.type === paymentConst.modes_value_object.safe) { if ((detail.status === status.checking || detail.status === status.checkNoPre) && detail.curAuditor && detail.curAuditor.aid === accountId) { detail.readOnly = false; } } return detail; } } return PaymentDetail; };