|
@@ -10,6 +10,9 @@
|
|
|
|
|
|
const auditConst = require('../const/audit');
|
|
const auditConst = require('../const/audit');
|
|
const auditType = auditConst.auditType;
|
|
const auditType = auditConst.auditType;
|
|
|
|
+const pushType = auditConst.pushType;
|
|
|
|
+const smsTypeConst = require('../const/sms_type');
|
|
|
|
+const wxConst = require('../const/wechat_template');
|
|
|
|
|
|
module.exports = app => {
|
|
module.exports = app => {
|
|
class SettleAudit extends app.BaseService {
|
|
class SettleAudit extends app.BaseService {
|
|
@@ -24,43 +27,44 @@ module.exports = app => {
|
|
this.tableName = 'settle_audit';
|
|
this.tableName = 'settle_audit';
|
|
}
|
|
}
|
|
|
|
|
|
- async getAuditors(settleId, times) {
|
|
|
|
- return await this.getAllDataByCondition({ where: { settle_id: settleId, audit_times: times } }); // 全部参与的审批人
|
|
|
|
|
|
+ // ***** 查询审批人相关
|
|
|
|
+ // 获取全部参与人
|
|
|
|
+ async getAuditors(settleId, auditTimes) {
|
|
|
|
+ return await this.getAllDataByCondition({ where: { settle_id: settleId, audit_times: auditTimes } }); // 全部参与的审批人
|
|
}
|
|
}
|
|
-
|
|
|
|
- async getAuditorGroup(settleId, times) {
|
|
|
|
- const auditors = await this.getAuditors(settleId, times); // 全部参与的审批人
|
|
|
|
|
|
+ // 获取全部参与人 分组
|
|
|
|
+ async getAuditorGroup(settleId, auditTimes) {
|
|
|
|
+ const auditors = await this.getAuditors(settleId, auditTimes); // 全部参与的审批人
|
|
return this.ctx.helper.groupAuditors(auditors, 'active_order');
|
|
return this.ctx.helper.groupAuditors(auditors, 'active_order');
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+ // 获取全部参与人 去重
|
|
async getUniqAuditors(settle) {
|
|
async getUniqAuditors(settle) {
|
|
const auditors = await this.getAuditors(settle.id, settle.audit_times); // 全部参与的审批人
|
|
const auditors = await this.getAuditors(settle.id, settle.audit_times); // 全部参与的审批人
|
|
const result = [];
|
|
const result = [];
|
|
auditors.forEach(x => {
|
|
auditors.forEach(x => {
|
|
- if (result.findIndex(r => { return x.aid === r.aid && x.audit_order === x.audit_order; }) < 0) {
|
|
|
|
|
|
+ if (result.findIndex(r => { return x.audit_id === r.audit_id && x.audit_order === x.audit_order; }) < 0) {
|
|
result.push(x);
|
|
result.push(x);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
-
|
|
|
|
- // 去重
|
|
|
|
- async getUniqAuditorsGroup(settleId, times) {
|
|
|
|
- const group = await this.getAuditorGroup(settleId, times);
|
|
|
|
|
|
+ // 获取全部参与人 分组 去重
|
|
|
|
+ async getUniqAuditorsGroup(settleId, auditTimes) {
|
|
|
|
+ const group = await this.getAuditorGroup(settleId, auditTimes);
|
|
return this.ctx.helper.groupAuditorsUniq(group);
|
|
return this.ctx.helper.groupAuditorsUniq(group);
|
|
}
|
|
}
|
|
-
|
|
|
|
- async getAuditorsByStatus(settleId, status, times) {
|
|
|
|
- const cur = await this.db.queryOne(`SELECT * From ${this.tableName} where settle_id = ? AND audit_times = ? AND audit_status = ? ORDER By audit_times DESC, audit_order DESC `, [settleId, times, status]);
|
|
|
|
|
|
+ // 获取某个状态的审批人
|
|
|
|
+ async getAuditorsByStatus(settleId, auditStatus, auditTimes) {
|
|
|
|
+ const cur = await this.db.queryOne(`SELECT * From ${this.tableName} where settle_id = ? AND audit_times = ? AND audit_status = ? ORDER By audit_times DESC, audit_order DESC `, [settleId, auditTimes, auditStatus]);
|
|
if (!cur) return [];
|
|
if (!cur) return [];
|
|
|
|
|
|
- return await this.getAllDataByCondition({ where: { settle_id: settleId, audit_times: times, audit_order: cur.audit_order}});
|
|
|
|
|
|
+ return await this.getAllDataByCondition({ where: { settle_id: settleId, audit_times: auditTimes, audit_order: cur.audit_order}});
|
|
}
|
|
}
|
|
-
|
|
|
|
- async getAuditorHistory(settleId, times, reverse = false) {
|
|
|
|
|
|
+ // 获取全部审批历史
|
|
|
|
+ async getAuditorHistory(settleId, auditTimes, reverse = false) {
|
|
const history = [];
|
|
const history = [];
|
|
- if (times >= 1) {
|
|
|
|
- for (let i = 1; i <= times; i++) {
|
|
|
|
|
|
+ if (auditTimes >= 1) {
|
|
|
|
+ for (let i = 1; i <= auditTimes; i++) {
|
|
const auditors = await this.getAuditors(settleId, i);
|
|
const auditors = await this.getAuditors(settleId, i);
|
|
const group = this.ctx.helper.groupAuditors(auditors);
|
|
const group = this.ctx.helper.groupAuditors(auditors);
|
|
const historyGroup = [];
|
|
const historyGroup = [];
|
|
@@ -71,19 +75,17 @@ module.exports = app => {
|
|
audit_type: g[0].audit_type, audit_order: g[0].audit_order,
|
|
audit_type: g[0].audit_type, audit_order: g[0].audit_order,
|
|
auditors: g
|
|
auditors: g
|
|
};
|
|
};
|
|
- if (his.audit_type === auditType.key.common) {
|
|
|
|
- his.name = g[0].name;
|
|
|
|
- } else {
|
|
|
|
- his.name = this.ctx.helper.transFormToChinese(his.audit_order) + '审';
|
|
|
|
- }
|
|
|
|
his.is_final = his.audit_order === max_order;
|
|
his.is_final = his.audit_order === max_order;
|
|
|
|
+ his.auditName = his.audit_order === 0 ? '原报' : (his.is_final ? '终审' : his.audit_order + '审');
|
|
|
|
+ his.auditCnName = his.audit_order === 0 ? '原报' : (his.is_final ? '终审' : this.ctx.helper.transFormToChinese(his.audit_order) + '审');
|
|
|
|
+ his.name = his.audit_type === auditType.key.common ? g[0].name : his.auditName;
|
|
let audit_time;
|
|
let audit_time;
|
|
g.forEach(x => {
|
|
g.forEach(x => {
|
|
- if (x.status === auditConst.settle.status.checkSkip) return;
|
|
|
|
- if (!his.status || x.status === auditConst.settle.status.checking) his.audit_status = x.audit_status;
|
|
|
|
|
|
+ if (x.audit_status === auditConst.settle.status.checkSkip) return;
|
|
|
|
+ if (!his.audit_status || x.audit_status === auditConst.settle.status.checking) his.audit_status = x.audit_status;
|
|
if (x.audit_time && (!audit_time || x.audit_time > audit_time)) {
|
|
if (x.audit_time && (!audit_time || x.audit_time > audit_time)) {
|
|
audit_time = x.audit_time;
|
|
audit_time = x.audit_time;
|
|
- if (his.status !== auditConst.settle.status.checking) his.audit_status = x.audit_status;
|
|
|
|
|
|
+ if (his.audit_status !== auditConst.settle.status.checking) his.audit_status = x.audit_status;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
if (audit_time) {
|
|
if (audit_time) {
|
|
@@ -104,7 +106,125 @@ module.exports = app => {
|
|
}
|
|
}
|
|
return history;
|
|
return history;
|
|
}
|
|
}
|
|
|
|
+ async getAllAuditors(tenderId) {
|
|
|
|
+ const sql =
|
|
|
|
+ 'SELECT sa.audit_id, sa.tid FROM ' + this.tableName + ' sa' +
|
|
|
|
+ ' LEFT JOIN ' + this.ctx.service.tender.tableName + ' t On sa.tid = t.id' +
|
|
|
|
+ ' WHERE t.id = ?' +
|
|
|
|
+ ' GROUP BY sa.audit_id';
|
|
|
|
+ const sqlParam = [tenderId];
|
|
|
|
+ return this.db.query(sql, sqlParam);
|
|
|
|
+ }
|
|
|
|
+ // ***** 查询审批人相关
|
|
|
|
|
|
|
|
+ // ***** 修改审批人相关
|
|
|
|
+ /**
|
|
|
|
+ * 获取 最新审核顺序
|
|
|
|
+ *
|
|
|
|
+ * @param {Number} settleId - 期id
|
|
|
|
+ * @param {Number} auditTimes - 第几次审批
|
|
|
|
+ * @return {Promise<number>}
|
|
|
|
+ */
|
|
|
|
+ async getNewOrder(settleId, auditTimes = 1) {
|
|
|
|
+ const sql = `SELECT Max(active_order) As max_order, Max(audit_order) As max_audit_order FROM ${this.tableName} Where settle_id = ? and audit_times = ?`;
|
|
|
|
+ const result = await this.db.queryOne(sql, [settleId, auditTimes]);
|
|
|
|
+ return result && result.max_order ? [result.max_order + 1, result.max_audit_order + 1] : [1, 1];
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * 同步审核人order
|
|
|
|
+ * @param transaction - 事务
|
|
|
|
+ * @param {Number} settleId - 结算期id
|
|
|
|
+ * @param {Number} auditOrder - 审核顺序(实际顺序)
|
|
|
|
+ * @param {Number} auditTimes - 第几次审批
|
|
|
|
+ * @param {String} selfOperate - 操作符(+/-)
|
|
|
|
+ * @return {Promise<*>}
|
|
|
|
+ * @private
|
|
|
|
+ */
|
|
|
|
+ async _syncAuditOrder(transaction, settleId, auditOrder, auditTimes, selfOperate = '-') {
|
|
|
|
+ this.initSqlBuilder();
|
|
|
|
+ this.sqlBuilder.setAndWhere('settle_id', {
|
|
|
|
+ value: settleId,
|
|
|
|
+ operate: '=',
|
|
|
|
+ });
|
|
|
|
+ this.sqlBuilder.setAndWhere('active_order', {
|
|
|
|
+ value: auditOrder,
|
|
|
|
+ operate: '>=',
|
|
|
|
+ });
|
|
|
|
+ this.sqlBuilder.setAndWhere('audit_times', {
|
|
|
|
+ value: auditTimes,
|
|
|
|
+ operate: '=',
|
|
|
|
+ });
|
|
|
|
+ this.sqlBuilder.setUpdateData('active_order', {
|
|
|
|
+ value: 1,
|
|
|
|
+ selfOperate: selfOperate,
|
|
|
|
+ });
|
|
|
|
+ this.sqlBuilder.setUpdateData('audit_order', {
|
|
|
|
+ value: 1,
|
|
|
|
+ selfOperate: selfOperate,
|
|
|
|
+ });
|
|
|
|
+ const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
|
|
|
|
+ const data = await transaction.query(sql, sqlParam);
|
|
|
|
+
|
|
|
|
+ return data;
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * 新增审核人
|
|
|
|
+ *
|
|
|
|
+ * @param {Number} settleId - 期id
|
|
|
|
+ * @param {Number} auditor - 审核人
|
|
|
|
+ * @param {Number} auditTimes - 第几次审批
|
|
|
|
+ * @param {Number} is_gdzs - 是否固定终审
|
|
|
|
+ * @return {Promise<number>}
|
|
|
|
+ */
|
|
|
|
+ async addAuditor(settleId, auditor, auditTimes = 1, is_gdzs = 0) {
|
|
|
|
+ let [newOrder, newAuditOrder] = await this.getNewOrder(settleId, auditTimes);
|
|
|
|
+ // 判断是否存在固定终审,存在则newOrder - 1并使终审order+1
|
|
|
|
+ newOrder = is_gdzs === 1 ? newOrder - 1 : newOrder;
|
|
|
|
+ newAuditOrder = is_gdzs === 1 ? newAuditOrder - 1 : newAuditOrder;
|
|
|
|
+
|
|
|
|
+ const transaction = await this.db.beginTransaction();
|
|
|
|
+ try {
|
|
|
|
+ if (is_gdzs) await this._syncAuditOrder(transaction, settleId, newOrder, auditTimes, '+');
|
|
|
|
+ const data = {
|
|
|
|
+ tid: this.ctx.tender.id, settle_id: settleId, audit_id: auditor.id,
|
|
|
|
+ name: auditor.name, company: auditor.company, role: auditor.role, mobile: auditor.mobile,
|
|
|
|
+ audit_times: auditTimes, active_order: newOrder, audit_status: auditConst.settle.status.uncheck,
|
|
|
|
+ audit_order: newAuditOrder, audit_type: auditType.key.common,
|
|
|
|
+ };
|
|
|
|
+ const result = await transaction.insert(this.tableName, data);
|
|
|
|
+ await transaction.commit();
|
|
|
|
+ return result.effectRows = 1;
|
|
|
|
+ } catch (err) {
|
|
|
|
+ await transaction.rollback();
|
|
|
|
+ throw err;
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * 移除审核人
|
|
|
|
+ *
|
|
|
|
+ * @param {Number} settleId - 期id
|
|
|
|
+ * @param {Number} auditorId - 审核人id
|
|
|
|
+ * @param {Number} auditTimes - 第几次审批
|
|
|
|
+ * @return {Promise<boolean>}
|
|
|
|
+ */
|
|
|
|
+ async deleteAuditor(settleId, auditorId, auditTimes = 1) {
|
|
|
|
+ const transaction = await this.db.beginTransaction();
|
|
|
|
+ try {
|
|
|
|
+ const condition = { settle_id: settleId, audit_id: auditorId, audit_times: auditTimes };
|
|
|
|
+ const auditor = await this.getDataByCondition(condition);
|
|
|
|
+ if (!auditor) throw '审批人不存在';
|
|
|
|
+ // 移除整个流程的人
|
|
|
|
+ await transaction.delete(this.tableName, { settle_id: settleId, active_order: auditor.active_order, audit_times: auditTimes});
|
|
|
|
+ await this._syncAuditOrder(transaction, settleId, auditor.active_order, auditTimes);
|
|
|
|
+ await transaction.commit();
|
|
|
|
+ } catch (err) {
|
|
|
|
+ await transaction.rollback();
|
|
|
|
+ throw err;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ // 拷贝上一期审批流程
|
|
async copyPreAuditors(transaction, preSettle, newSettle) {
|
|
async copyPreAuditors(transaction, preSettle, newSettle) {
|
|
const auditors = preSettle ? await this.getUniqAuditors(preSettle) : [];
|
|
const auditors = preSettle ? await this.getUniqAuditors(preSettle) : [];
|
|
const newAuditors = [];
|
|
const newAuditors = [];
|
|
@@ -130,7 +250,434 @@ module.exports = app => {
|
|
const result = await transaction.insert(this.tableName, newAuditors);
|
|
const result = await transaction.insert(this.tableName, newAuditors);
|
|
if (result.affectedRows !== newAuditors.length) throw '初始化审批流程错误';
|
|
if (result.affectedRows !== newAuditors.length) throw '初始化审批流程错误';
|
|
}
|
|
}
|
|
|
|
+ // 固定审批流-更新
|
|
|
|
+ async updateNewAuditList(settle, newList) {
|
|
|
|
+ const newAuditsInfo = await this.ctx.service.projectAccount.getAllDataByCondition({ where: { id: newList.map(x => { return x.audit_id; })} });
|
|
|
|
+ const transaction = await this.db.beginTransaction();
|
|
|
|
+ try {
|
|
|
|
+ // 先删除旧的审批流,再添加新的
|
|
|
|
+ await transaction.query(`DELETE FROM ${this.tableName} where settle_id = ? and audit_times = ? and audit_order > 0`, [settle.id, settle.audit_times]);
|
|
|
|
+ // todo 协同
|
|
|
|
+ //await transaction.delete(this.ctx.service.settleAuditAss.tableName, { settle_id: settle.id, audit_times: settle.audit_times });
|
|
|
|
+ const newAuditors = [];
|
|
|
|
+ for (const auditor of newList) {
|
|
|
|
+ const auditorInfo = newAuditsInfo.find(x => { return x.id === auditor.audit_id; });
|
|
|
|
+ if (!auditorInfo) throw '配置的审批人不存在';
|
|
|
|
+ newAuditors.push({
|
|
|
|
+ tid: settle.tid, settle_id: settle.id, audit_id: auditor.audit_id,
|
|
|
|
+ name: auditorInfo.name, company: auditorInfo.company, role: auditorInfo.role, mobile: auditorInfo.mobile,
|
|
|
|
+ audit_times: settle.audit_times, active_order: auditor.audit_order, audit_status: auditConst.settle.status.uncheck,
|
|
|
|
+ audit_type: auditor.audit_type, audit_order: auditor.audit_order,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ if(newAuditors.length > 0) await transaction.insert(this.tableName, newAuditors);
|
|
|
|
+ await transaction.commit();
|
|
|
|
+ } catch (err) {
|
|
|
|
+ await transaction.rollback();
|
|
|
|
+ throw err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 固定终审-更新
|
|
|
|
+ async updateLastAudit(settle, auditList, lastId) {
|
|
|
|
+ const lastUser = await this.ctx.service.projectAccount.getDataById(lastId);
|
|
|
|
+ const transaction = await this.db.beginTransaction();
|
|
|
|
+ try {
|
|
|
|
+ // 先判断auditList里的aid是否与lastId相同,相同则删除并重新更新order
|
|
|
|
+ const existAudit = auditList.find(x => { return x.audit_id === lastId });
|
|
|
|
+ let auditOrder = auditList.length > 0 ? auditList.reduce((rst, a) => { return Math.max(rst, a.active_order)}, 0) + 1 : 1; // 最大值 + 1
|
|
|
|
+ if (existAudit) {
|
|
|
|
+ await transaction.delete(this.tableName, { settle_id: settle.id, audit_times: settle.audit_times, audit_id: lastId });
|
|
|
|
+ const sameOrder = auditList.filter(x => { return x.active_order === existAudit.active_order });
|
|
|
|
+ if (sameOrder.length === 1) {
|
|
|
|
+ const updateData = [];
|
|
|
|
+ auditList.forEach(x => {
|
|
|
|
+ if (x.active_order <= existAudit.active_order) return;
|
|
|
|
+ updateData.push({id: x.id, active_order: x.active_order - 1, audit_order: x.audit_order - 1});
|
|
|
|
+ });
|
|
|
|
+ if (updateData.length > 0) {
|
|
|
|
+ await transaction.updateRows(updateData);
|
|
|
|
+ }
|
|
|
|
+ auditOrder = auditOrder - 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 添加终审
|
|
|
|
+ const newAuditor = {
|
|
|
|
+ tid: settle.tid, settle_id: settle.id, audit_id: lastId,
|
|
|
|
+ name: lastUser.name, company: lastUser.company, role: lastUser.role, mobile: lastUser.mobile,
|
|
|
|
+ audit_times: settle.audit_times, active_order: auditOrder, audit_status: auditConst.settle.status.uncheck,
|
|
|
|
+ audit_type: auditType.key.common, audit_order: auditOrder,
|
|
|
|
+ };
|
|
|
|
+ await transaction.insert(this.tableName, newAuditor);
|
|
|
|
+ await transaction.commit();
|
|
|
|
+ } catch (err) {
|
|
|
|
+ await transaction.rollback();
|
|
|
|
+ throw err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // ***** 修改审批人相关
|
|
|
|
+
|
|
|
|
+ // ***** 审批操作
|
|
|
|
+ /**
|
|
|
|
+ * 用于添加推送所需的content内容
|
|
|
|
+ * @param {Number} pid 项目id
|
|
|
|
+ * @param {Number} tid 台账id
|
|
|
|
+ * @param {Number} sid 期id
|
|
|
|
+ * @param {Number} uid 审核人id
|
|
|
|
+ */
|
|
|
|
+ async _getNoticeContent(pid, tid, sid, uid, opinion = '') {
|
|
|
|
+ const noticeSql =
|
|
|
|
+ 'SELECT * FROM (SELECT ' +
|
|
|
|
+ ' t.`id` As `tid`, t.`name`, s.`settle_order` as `order`, pa.`name` As `su_name`, pa.role As `su_role`' +
|
|
|
|
+ ` FROM (SELECT * FROM ${this.ctx.service.tender.tableName} WHERE id = ? ) As t` +
|
|
|
|
+ ` LEFT JOIN ${this.ctx.service.settle.tableName} As s On s.id = ?` +
|
|
|
|
+ ` LEFT JOIN ${this.ctx.service.projectAccount.tableName} As pa ON pa.id = ?` +
|
|
|
|
+ ' WHERE t.`project_id` = ? ) as new_t GROUP BY new_t.`tid`';
|
|
|
|
+ const noticeSqlParam = [tid, sid, uid, pid];
|
|
|
|
+ const content = await this.db.query(noticeSql, noticeSqlParam);
|
|
|
|
+ if (content.length) {
|
|
|
|
+ content[0].opinion = opinion;
|
|
|
|
+ }
|
|
|
|
+ return content.length ? JSON.stringify(content[0]) : '';
|
|
|
|
+ }
|
|
|
|
+ async start(settle) {
|
|
|
|
+ const audits = await this.getAllDataByCondition({ where: { settle_id: settle.id, audit_times: settle.audit_times, audit_order: 1 } });
|
|
|
|
+ if (audits.length === 0) {
|
|
|
|
+ if(this.ctx.tender.info.shenpi.settle === shenpiConst.sp_status.gdspl) {
|
|
|
|
+ throw '请联系管理员添加审批人';
|
|
|
|
+ } else {
|
|
|
|
+ throw '请先选择审批人,再上报数据';
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const transaction = await this.db.beginTransaction();
|
|
|
|
+ try {
|
|
|
|
+ const audit_time = new Date();
|
|
|
|
+ // 更新原报数据
|
|
|
|
+ await transaction.update(this.tableName, { audit_status: auditConst.settle.status.checked, audit_time }, { where: { settle_id: settle.id, audit_times: settle.audit_times, audit_order: 0 } });
|
|
|
|
+ // 更新下一审批人数据
|
|
|
|
+ const updateData = audits.map(x => { return { id: x.id, audit_status: auditConst.settle.status.checking } });
|
|
|
|
+ await transaction.updateRows(this.tableName, updateData);
|
|
|
|
+ // 生成结算台账
|
|
|
|
+ const settleSum = await this.ctx.service.settle.doSettle(transaction, settle);
|
|
|
|
+ // todo 计算部分缓存汇总数据
|
|
|
|
+ await transaction.update(this.ctx.service.settle.tableName, {
|
|
|
|
+ id: settle.id, audit_status: auditConst.settle.status.checking,
|
|
|
|
+ ...settleSum,
|
|
|
|
+ });
|
|
|
|
+ // 多人协同,取消下一审批人存在的锁定
|
|
|
|
+ // await this.ctx.service.settleAuditAss.cancelLock(settle, audits.map(x => { return x.audit_id; }), transaction);
|
|
|
|
+
|
|
|
|
+ // todo 添加短信通知-需要审批提醒功能
|
|
|
|
+ const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + settle.tid + '/settle/' + settle.settle_order);
|
|
|
|
+ const auditIds = this._.map(audits, 'audit_id');
|
|
|
|
+ const users = this._.map(settle.auditAssists.filter(x => { return auditIds.indexOf(x.user_id) >= 0; }), 'ass_user_id');
|
|
|
|
+ users.push(...auditIds);
|
|
|
|
+ // await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), SmsAliConst.template.settle_check, {
|
|
|
|
+ // qi: settle.audit_order,
|
|
|
|
+ // code: shenpiUrl,
|
|
|
|
+ // });
|
|
|
|
+ // 微信模板通知
|
|
|
|
+ const wechatData = {
|
|
|
|
+ wap_url: shenpiUrl,
|
|
|
|
+ qi: settle.settle_order,
|
|
|
|
+ status: wxConst.status.check,
|
|
|
|
+ tips: wxConst.tips.check,
|
|
|
|
+ code: this.ctx.session.sessionProject.code,
|
|
|
|
+ };
|
|
|
|
+ await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), wxConst.template.settle, wechatData);
|
|
|
|
+
|
|
|
|
+ // todo 上报/审批 - 检查三方特殊推送
|
|
|
|
+ // await this.ctx.service.specMsg.addSettleMsg(transaction, this.ctx.session.sessionProject.id, settle, pushOperate.settle.flow);
|
|
|
|
+ await transaction.commit();
|
|
|
|
+ } catch (err) {
|
|
|
|
+ await transaction.rollback();
|
|
|
|
+ throw err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ async _checked(settle, opinion) {
|
|
|
|
+ const accountId = this.ctx.session.sessionUser.accountId;
|
|
|
|
+ const time = new Date();
|
|
|
|
+ const selfAudit = settle.curAuditors.find(x => { return x.audit_id === accountId; });
|
|
|
|
+ if (!selfAudit) throw '当前标段您无权审批';
|
|
|
|
+ const nextAudits = await this.getAllDataByCondition({ where: { settle_id: settle.id, audit_times: settle.audit_times, active_order: selfAudit.active_order + 1 } });
|
|
|
|
+
|
|
|
|
+ const transaction = await this.db.beginTransaction();
|
|
|
|
+ try {
|
|
|
|
+ // 添加通知
|
|
|
|
+ const noticeContent = await this._getNoticeContent(this.ctx.session.sessionProject.id, settle.tid, settle.id, accountId, opinion);
|
|
|
|
+ const defaultNoticeRecord = {
|
|
|
|
+ pid: this.ctx.session.sessionProject.id,
|
|
|
|
+ type: pushType.settle,
|
|
|
|
+ status: auditConst.settle.status.checked,
|
|
|
|
+ content: noticeContent,
|
|
|
|
+ };
|
|
|
|
+ const records = settle.userIds.map(x => {
|
|
|
|
+ return { uid: x, ...defaultNoticeRecord };
|
|
|
|
+ });
|
|
|
|
+ await transaction.insert('zh_notice', records);
|
|
|
|
+
|
|
|
|
+ // 更新本人审批状态
|
|
|
|
+ await transaction.update(this.tableName, {
|
|
|
|
+ id: selfAudit.id,
|
|
|
|
+ audit_status: auditConst.settle.status.checked, opinion: opinion,
|
|
|
|
+ audit_time: time,
|
|
|
|
+ });
|
|
|
|
+ let auditStatus;
|
|
|
|
+ if (settle.curAuditors.length === 1 || selfAudit.audit_type !== auditType.key.and) {
|
|
|
|
+ // 或签更新他人审批状态
|
|
|
|
+ if (selfAudit.audit_type === auditType.key.or) {
|
|
|
|
+ const updateOther = [];
|
|
|
|
+ for (const audit of settle.curAuditors) {
|
|
|
|
+ if (audit.audit_id === selfAudit.audit_id) continue;
|
|
|
|
+ updateOther.push({
|
|
|
|
+ id: audit.id,
|
|
|
|
+ audit_status: auditConst.settle.status.checkSkip,
|
|
|
|
+ opinion: '',
|
|
|
|
+ audit_time: time,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ if (updateOther.length > 0) transaction.updateRows(this.tableName, updateOther);
|
|
|
|
+ }
|
|
|
|
+ // 无下一审核人表示,审核结束
|
|
|
|
+ auditStatus = nextAudits.length > 0 ? auditConst.settle.status.checking : auditConst.settle.status.checked;
|
|
|
|
+ if (nextAudits.length > 0) {
|
|
|
|
+ // 流程至下一审批人
|
|
|
|
+ const updateData = nextAudits.map(x => { return { id: x.id, audit_status: auditConst.settle.status.checking }; });
|
|
|
|
+ await transaction.updateRows(this.tableName, updateData);
|
|
|
|
+ // todo 多人协同,取消下一审批人存在的锁定
|
|
|
|
+ // await this.ctx.service.settleAuditAss.cancelLock(settle, nextAudits.map(x => { return x.audit_id; }), transaction);
|
|
|
|
+
|
|
|
|
+ // todo 添加短信通知-需要审批提醒功能
|
|
|
|
+ const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + this.ctx.tender.id + '/settle/' + settle.settle_order);
|
|
|
|
+ const nextAuditIds = this._.map(nextAudits, 'audit_id');
|
|
|
|
+ const users = this._.map(this._.filter(this.ctx.auditAssists, function (x) { return nextAuditIds.indexOf(x.user_id) >= 0; }), 'ass_user_id');
|
|
|
|
+ users.push(...nextAuditIds);
|
|
|
|
+ // await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), SmsAliConst.template.settle_check, {
|
|
|
|
+ // qi: settle.settle_order,
|
|
|
|
+ // code: shenpiUrl,
|
|
|
|
+ // });
|
|
|
|
+ // 微信模板通知
|
|
|
|
+ const wechatData = {
|
|
|
|
+ wap_url: shenpiUrl,
|
|
|
|
+ qi: settle.settle_order,
|
|
|
|
+ status: wxConst.status.check,
|
|
|
|
+ tips: wxConst.tips.check,
|
|
|
|
+ code: this.ctx.session.sessionProject.code,
|
|
|
|
+ };
|
|
|
|
+ await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), wxConst.template.settle, wechatData);
|
|
|
|
+ } else {
|
|
|
|
+ // 添加短信通知-审批通过提醒功能
|
|
|
|
+ const users = this._.uniq(settle.userIds);
|
|
|
|
+ // await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JS, smsTypeConst.judge.result.toString(), SmsAliConst.template.settle_result, {
|
|
|
|
+ // qi: settle.settle_order,
|
|
|
|
+ // status: SmsAliConst.status.success,
|
|
|
|
+ // });
|
|
|
|
|
|
|
|
+ // 微信模板通知
|
|
|
|
+ const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + this.ctx.tender.id + '/settle/' + settle.settle_order);
|
|
|
|
+ const wechatData = {
|
|
|
|
+ wap_url: shenpiUrl,
|
|
|
|
+ qi: settle.settle_order,
|
|
|
|
+ status: wxConst.status.success,
|
|
|
|
+ tips: wxConst.tips.success,
|
|
|
|
+ code: this.ctx.session.sessionProject.code,
|
|
|
|
+ };
|
|
|
|
+ await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.result.toString(), wxConst.template.settle, wechatData);
|
|
|
|
+ // todo 审批通过 - 检查三方特殊推送
|
|
|
|
+ // await this.ctx.service.specMsg.addSettleMsg(transaction, this.ctx.session.sessionProject.id, settle, pushOperate.settle.checked);
|
|
|
|
+ }
|
|
|
|
+ // todo 上报/审批 - 检查三方特殊推送
|
|
|
|
+ // await this.ctx.service.specMsg.addSettleMsg(transaction, this.ctx.session.sessionProject.id, settle, pushOperate.settle.flow);
|
|
|
|
+ } else {
|
|
|
|
+ auditStatus = auditConst.settle.status.checking;
|
|
|
|
+ }
|
|
|
|
+ // 同步 期信息
|
|
|
|
+ await transaction.update(this.ctx.service.settle.tableName, { id: settle.id, audit_status: auditStatus });
|
|
|
|
+ await transaction.commit();
|
|
|
|
+ } catch (err) {
|
|
|
|
+ await transaction.rollback();
|
|
|
|
+ throw err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ async _checkNo(settle, opinion) {
|
|
|
|
+ const pid = this.ctx.session.sessionProject.id;
|
|
|
|
+ const accountId = this.ctx.session.sessionUser.accountId;
|
|
|
|
+ const time = new Date();
|
|
|
|
+ // 整理当前流程审核人状态更新
|
|
|
|
+ const selfAudit = settle.curAuditors.find(x => { return x.audit_id === accountId; });
|
|
|
|
+ if (!selfAudit) throw '当前标段您无权审批';
|
|
|
|
+ const auditors = await this.getUniqAuditors(settle); // 全部参与的审批人
|
|
|
|
+ const newAuditors = auditors.map(x => {
|
|
|
|
+ return {
|
|
|
|
+ tid: settle.tid, settle_id: settle.id, audit_id: x.audit_id,
|
|
|
|
+ audit_times: settle.audit_times + 1, audit_order: x.audit_order, audit_type: x.audit_type,
|
|
|
|
+ active_order: x.audit_order, audit_status: auditConst.settle.status.uncheck,
|
|
|
|
+ name: x.name, company: x.company, role: x.role, mobile: x.mobile,
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ const transaction = await this.db.beginTransaction();
|
|
|
|
+ try {
|
|
|
|
+ // 添加提醒
|
|
|
|
+ const noticeContent = await this._getNoticeContent(pid, selfAudit.tid, settle.id, selfAudit.audit_id, opinion);
|
|
|
|
+ const defaultNoticeRecord = { pid, type: pushType.settle, status: auditConst.settle.status.checkNo, content: noticeContent };
|
|
|
|
+ const records = settle.userIds.map(x => {
|
|
|
|
+ return { uid: x, ...defaultNoticeRecord };
|
|
|
|
+ });
|
|
|
|
+ await transaction.insert(this.ctx.service.noticePush.tableName, records);
|
|
|
|
+
|
|
|
|
+ // 更新审批人状态数据
|
|
|
|
+ const updateData = [];
|
|
|
|
+ settle.curAuditors.forEach(x => {
|
|
|
|
+ if (x.audit_id === selfAudit.audit_id) {
|
|
|
|
+ updateData.push({ id: x.id, audit_status: auditConst.settle.status.checkNo, opinion: opinion, audit_time: time});
|
|
|
|
+ } else {
|
|
|
|
+ updateData.push({ id: x.id, audit_status: auditConst.settle.status.checkSkip, opinion: '', audit_time: null});
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ await transaction.updateRows(this.tableName, updateData);
|
|
|
|
+ // 更新 期信息
|
|
|
|
+ await transaction.update(this.ctx.service.settle.tableName, {
|
|
|
|
+ id: settle.id, audit_status: auditConst.settle.status.checkNo, audit_times: settle.audit_times + 1,
|
|
|
|
+ });
|
|
|
|
+ // 拷贝新一次审核流程列表
|
|
|
|
+ await transaction.insert(this.tableName, newAuditors);
|
|
|
|
+ // todo 锁定本人数据,保留锁定数据相关确认状态
|
|
|
|
+ // await this.ctx.service.settleAuditAss.lockConfirm4CheckNo(settle, curAuditorIds, auditors, transaction);
|
|
|
|
+
|
|
|
|
+ // todo 添加短信通知-审批退回提醒功能
|
|
|
|
+ const users = this._.uniq(settle.userIds);
|
|
|
|
+ // await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JS, smsTypeConst.judge.result.toString(), SmsAliConst.template.settle_result, {
|
|
|
|
+ // qi: settle.settle_order, status: SmsAliConst.status.back,
|
|
|
|
+ // });
|
|
|
|
+ // 微信模板通知
|
|
|
|
+ const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + settle.tid + '/settle/' + settle.settle_order);
|
|
|
|
+ const wechatData = {
|
|
|
|
+ wap_url: shenpiUrl,
|
|
|
|
+ qi: settle.settle_order,
|
|
|
|
+ status: wxConst.status.back,
|
|
|
|
+ tips: wxConst.tips.back,
|
|
|
|
+ code: this.ctx.session.sessionProject.code,
|
|
|
|
+ };
|
|
|
|
+ await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.result.toString(), wxConst.template.settle, wechatData);
|
|
|
|
+ // todo 上报/审批 - 检查三方特殊推送
|
|
|
|
+ // await this.ctx.service.specMsg.addSettleMsg(transaction, pid, settle, pushOperate.settle.flow);
|
|
|
|
+ await transaction.commit();
|
|
|
|
+ } catch (err) {
|
|
|
|
+ await transaction.rollback();
|
|
|
|
+ throw err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ async _checkNoPre(settle, opinion) {
|
|
|
|
+ const pid = this.ctx.session.sessionProject.id;
|
|
|
|
+ const accountId = this.ctx.session.sessionUser.accountId;
|
|
|
|
+ const time = new Date();
|
|
|
|
+ // 整理当前流程审核人状态更新
|
|
|
|
+ const selfAudit = settle.curAuditors.find(x => { return x.audit_id === accountId; });
|
|
|
|
+ if (!selfAudit) throw '当前标段您无权审批';
|
|
|
|
+ const preAuditors = settle.userGroups.find(x => { return x[0].audit_order === selfAudit.audit_order - 1; });
|
|
|
|
+
|
|
|
|
+ const transaction = await this.db.beginTransaction();
|
|
|
|
+ try {
|
|
|
|
+ // 添加通知
|
|
|
|
+ const noticeContent = await this._getNoticeContent(pid, settle.tid, settle.id, selfAudit.audit_id, opinion);
|
|
|
|
+ const defaultNoticeRecord = {
|
|
|
|
+ pid, type: pushType.settle, status: auditConst.settle.status.checkNoPre, content: noticeContent,
|
|
|
|
+ };
|
|
|
|
+ const records = settle.userIds.map(x => {
|
|
|
|
+ return { uid: x, ...defaultNoticeRecord };
|
|
|
|
+ });
|
|
|
|
+ await transaction.insert('zh_notice', records);
|
|
|
|
+
|
|
|
|
+ // 更新同一流程所有审批人状态
|
|
|
|
+ const updateData = [];
|
|
|
|
+ for (const audit of settle.curAuditors) {
|
|
|
|
+ if (audit.audit_id === selfAudit.audit_id) {
|
|
|
|
+ updateData.push({
|
|
|
|
+ id: audit.id, audit_status: auditConst.settle.status.checkNoPre, opinion, audit_time: time,
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ updateData.push({
|
|
|
|
+ id: audit.id, audit_status: auditConst.settle.status.checkSkip, opinion: '', audit_time: null,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ await transaction.updateRows(this.tableName, updateData);
|
|
|
|
+
|
|
|
|
+ // 顺移其后审核人流程顺序
|
|
|
|
+ const sql = 'UPDATE ' + this.tableName + ' SET `active_order` = `active_order` + 2 WHERE settle_id = ? AND audit_times = ? AND `active_order` > ?';
|
|
|
|
+ await transaction.query(sql, [settle.id, selfAudit.audit_times, selfAudit.active_order]);
|
|
|
|
+ // 上一审批人,当前审批人 再次添加至流程
|
|
|
|
+ const newAuditors = [];
|
|
|
|
+ preAuditors.forEach(x => {
|
|
|
|
+ newAuditors.push({
|
|
|
|
+ tid: x.tid, settle_id: x.settle_id, audit_id: x.audit_id,
|
|
|
|
+ audit_times: x.audit_times, audit_order: selfAudit.audit_order - 1,
|
|
|
|
+ audit_status: auditConst.settle.status.checking,
|
|
|
|
+ audit_type: x.audit_type, active_order: selfAudit.active_order + 1,
|
|
|
|
+ name: x.name, company: x.company, role: x.role, mobile: x.mobile,
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ settle.flowAuditors.forEach(x => {
|
|
|
|
+ newAuditors.push({
|
|
|
|
+ tid: x.tid, settle_id: x.settle_id, audit_id: x.audit_id,
|
|
|
|
+ audit_times: x.audit_times, active_order: selfAudit.active_order + 2,
|
|
|
|
+ audit_status: auditConst.settle.status.uncheck,
|
|
|
|
+ audit_type: x.audit_type, audit_order: x.audit_order,
|
|
|
|
+ name: x.name, company: x.company, role: x.role, mobile: x.mobile,
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ await transaction.insert(this.tableName, newAuditors);
|
|
|
|
+
|
|
|
|
+ const preAuditorIds = preAuditors.map(x => { return x.audit_id; });
|
|
|
|
+ // todo 锁定本人数据,保留锁定数据相关确认状态
|
|
|
|
+ // await this.ctx.service.settleAuditAss.lockConfirm4CheckNoPre(settle, settle.curAuditorIds, preAuditorIds, transaction);
|
|
|
|
+
|
|
|
|
+ // 同步 期信息
|
|
|
|
+ await transaction.update(this.ctx.service.settle.tableName, {
|
|
|
|
+ id: settle.id, audit_status: auditConst.settle.status.checkNoPre,
|
|
|
|
+ });
|
|
|
|
+ const shenpiUrl = await this.ctx.helper.urlToShort(this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + settle.tid + '/settle/' + settle.settle_order);
|
|
|
|
+ const users = this._.map(settle.auditAssists.filter(x => {return preAuditorIds.indexOf(x.user_id) >= 0 }), 'ass_user_id');
|
|
|
|
+ users.push(...preAuditorIds);
|
|
|
|
+ // await this.ctx.helper.sendAliSms(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), SmsAliConst.template.settle_check, {
|
|
|
|
+ // qi: settle.settle_order,
|
|
|
|
+ // code: shenpiUrl,
|
|
|
|
+ // });
|
|
|
|
+ // 微信模板通知
|
|
|
|
+ const wechatData = {
|
|
|
|
+ wap_url: shenpiUrl,
|
|
|
|
+ qi: settle.settle_order,
|
|
|
|
+ status: wxConst.status.check,
|
|
|
|
+ tips: wxConst.tips.check,
|
|
|
|
+ code: this.ctx.session.sessionProject.code,
|
|
|
|
+ };
|
|
|
|
+ await this.ctx.helper.sendWechat(users, smsTypeConst.const.JS, smsTypeConst.judge.approval.toString(), wxConst.template.settle, wechatData);
|
|
|
|
+
|
|
|
|
+ // todo 上报/审批 - 检查三方特殊推送
|
|
|
|
+ // await this.ctx.service.specMsg.addSettleMsg(transaction, pid, settle, pushOperate.settle.flow);
|
|
|
|
+ await transaction.commit();
|
|
|
|
+ } catch (err) {
|
|
|
|
+ await transaction.rollback();
|
|
|
|
+ throw err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ async check(settle, checkType, opinion = '') {
|
|
|
|
+ switch (checkType) {
|
|
|
|
+ case auditConst.settle.status.checked:
|
|
|
|
+ await this._checked(settle, opinion);
|
|
|
|
+ break;
|
|
|
|
+ case auditConst.settle.status.checkNo:
|
|
|
|
+ await this._checkNo(settle, opinion);
|
|
|
|
+ break;
|
|
|
|
+ case auditConst.settle.status.checkNoPre:
|
|
|
|
+ await this._checkNoPre(settle, opinion);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ throw '无效审批操作';
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // ***** 审批操作
|
|
}
|
|
}
|
|
|
|
|
|
return SettleAudit;
|
|
return SettleAudit;
|