|
|
@@ -15,6 +15,13 @@ module.exports = app => {
|
|
|
this.tableName = 'advance_audit';
|
|
|
}
|
|
|
|
|
|
+ async checkAuditNodes(vid, times) {
|
|
|
+ const rows = await this.getAllDataByCondition({ where: { vid, times } });
|
|
|
+ if (rows.some(x => !(x.audit_order > 0) || x.audit_type !== auditType.key.common)) {
|
|
|
+ throw '请先回填当前预付款的审批节点序号和普通审批类型';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 获取审核人流程列表
|
|
|
* @param {Number} vid 预付款记录id
|
|
|
@@ -22,12 +29,9 @@ module.exports = app => {
|
|
|
* @return {Promise<Array>} 查询结果集
|
|
|
*/
|
|
|
async getAuditGroupByList(vid, times = 1) {
|
|
|
- const sql =
|
|
|
- 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, la.`times`, la.`vid`, la.`order` ' +
|
|
|
- ' FROM ?? AS la Left Join ?? AS pa On la.`audit_id` = pa.`id`' +
|
|
|
- ' WHERE la.`vid` = ? and la.`times` = ? GROUP BY la.`audit_id` ORDER BY la.`order`';
|
|
|
- const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, vid, times];
|
|
|
- return await this.db.query(sql, sqlParam);
|
|
|
+ const auditors = await this.getAuditors(vid, times);
|
|
|
+ // 一个节点可因退回、重审产生多条过程记录,流程展示取该节点最新记录。
|
|
|
+ return this._.sortBy(this._.uniqBy(auditors.slice().reverse(), 'audit_order'), 'audit_order');
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -39,7 +43,7 @@ module.exports = app => {
|
|
|
async getAuditorsWithOwner(vid, times = 1) {
|
|
|
const result = await this.getAuditGroupByList(vid, times);
|
|
|
const sql =
|
|
|
- 'SELECT pa.`id` As audit_id, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As vid, 0 As `order`' +
|
|
|
+ 'SELECT pa.`id` As audit_id, pa.`name`, pa.`company`, pa.`role`, ? As times, ? As vid, 0 As `order`, 0 As audit_order, 1 As audit_type' +
|
|
|
' FROM ' + this.ctx.service.advance.tableName + ' As s' +
|
|
|
' LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa' +
|
|
|
' ON s.uid = pa.id' +
|
|
|
@@ -72,12 +76,18 @@ module.exports = app => {
|
|
|
* @return {Boolean} 是否插入成功
|
|
|
*/
|
|
|
async addAuditor(tid, vid, audit_id, times = 1, type, is_gdzs = 0) {
|
|
|
+ await this.checkAuditNodes(vid, times);
|
|
|
const transaction = await this.db.beginTransaction();
|
|
|
try {
|
|
|
- let newOrder = await this.getNewOrder(vid, times);
|
|
|
+ const audits = await transaction.select(this.tableName, { where: { vid, times }, orders: [['order', 'asc']] });
|
|
|
+ let newOrder = audits.length ? audits[audits.length - 1].order + 1 : 1;
|
|
|
+ let newAuditOrder = audits.length ? Math.max(...audits.map(x => x.audit_order)) + 1 : 1;
|
|
|
// 判断是否存在固定终审,存在则newOrder - 1并使终审order+1
|
|
|
- newOrder = is_gdzs === 1 ? newOrder - 1 : newOrder;
|
|
|
- if (is_gdzs) await this._syncOrderByDelete(transaction, vid, newOrder, times, '+');
|
|
|
+ if (is_gdzs && audits.length) {
|
|
|
+ newOrder--;
|
|
|
+ newAuditOrder--;
|
|
|
+ await this._syncOrderByDelete(transaction, vid, newOrder, times, '+', newAuditOrder);
|
|
|
+ }
|
|
|
const record = {
|
|
|
tid,
|
|
|
vid,
|
|
|
@@ -85,6 +95,8 @@ module.exports = app => {
|
|
|
audit_id,
|
|
|
times,
|
|
|
order: newOrder,
|
|
|
+ audit_order: newAuditOrder,
|
|
|
+ audit_type: auditType.key.common,
|
|
|
status: auditConst.status.uncheck,
|
|
|
};
|
|
|
const result = await transaction.insert(this.tableName, record);
|
|
|
@@ -105,6 +117,7 @@ module.exports = app => {
|
|
|
* @return {Promise<boolean>}
|
|
|
*/
|
|
|
async deleteAuditor(vid, audit_id, times = 1) {
|
|
|
+ await this.checkAuditNodes(vid, times);
|
|
|
const transaction = await this.db.beginTransaction();
|
|
|
try {
|
|
|
const condition = { vid, audit_id, times };
|
|
|
@@ -112,7 +125,7 @@ module.exports = app => {
|
|
|
if (!auditor) {
|
|
|
throw '该审核人不存在';
|
|
|
}
|
|
|
- await this._syncOrderByDelete(transaction, vid, auditor.order, times);
|
|
|
+ await this._syncOrderByDelete(transaction, vid, auditor.order, times, '-', auditor.audit_order);
|
|
|
await transaction.delete(this.tableName, condition);
|
|
|
await transaction.commit();
|
|
|
} catch (err) {
|
|
|
@@ -131,7 +144,7 @@ module.exports = app => {
|
|
|
* @return {Promise<*>} 查询结果集
|
|
|
* @private
|
|
|
*/
|
|
|
- async _syncOrderByDelete(transaction, vid, order, times, selfOperate = '-') {
|
|
|
+ async _syncOrderByDelete(transaction, vid, order, times, selfOperate = '-', auditOrder = order) {
|
|
|
this.initSqlBuilder();
|
|
|
this.sqlBuilder.setAndWhere('vid', {
|
|
|
value: this.db.escape(vid),
|
|
|
@@ -151,6 +164,8 @@ module.exports = app => {
|
|
|
});
|
|
|
const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
|
|
|
const data = await transaction.query(sql, sqlParam);
|
|
|
+ // 节点序号与过程序号分开移动,退回上一审后两者不再相等。
|
|
|
+ await transaction.query('UPDATE ?? SET audit_order = audit_order ' + (selfOperate === '+' ? '+' : '-') + ' 1 WHERE vid = ? AND times = ? AND audit_order >= ?', [this.tableName, vid, times, auditOrder]);
|
|
|
return data;
|
|
|
}
|
|
|
|
|
|
@@ -162,7 +177,7 @@ module.exports = app => {
|
|
|
*/
|
|
|
async getCurAuditor(vid, times = 1) {
|
|
|
const sql =
|
|
|
- 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`create_time`, la.`end_time` ' +
|
|
|
+ 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`audit_order`, la.`audit_type`, la.`order`, la.`status`, la.`opinion`, la.`create_time`, la.`end_time` ' +
|
|
|
' FROM ?? AS la Left Join ?? AS pa On la.`audit_id` = pa.`id` ' +
|
|
|
' WHERE la.`vid` = ? and la.`status` = ? and la.`times` = ?';
|
|
|
const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, vid, auditConst.status.checking, times];
|
|
|
@@ -177,12 +192,12 @@ module.exports = app => {
|
|
|
*/
|
|
|
async getAuditors(vid, times = 1) {
|
|
|
const sql =
|
|
|
- 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`type`, la.`order`, la.`status`, la.`opinion`, la.`create_time`, la.`end_time`, g.`sort` ' +
|
|
|
- 'FROM ?? AS la, ?? AS pa, (SELECT t1.`audit_id`,(@i:=@i+1) as `sort` FROM (SELECT t.`audit_id`, t.`order` FROM (select `audit_id`, `order` from ?? WHERE `vid` = ? AND `times` = ? ORDER BY `order` LIMIT 200) t GROUP BY t.`audit_id` ORDER BY t.`order`) t1, (select @i:=0) as it) as g ' +
|
|
|
- 'WHERE la.`vid` = ? and la.`times` = ? and la.`audit_id` = pa.`id` and g.`audit_id` = la.`audit_id` order by la.`order`';
|
|
|
- const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, this.tableName, vid, times, vid, times];
|
|
|
+ 'SELECT la.*, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`audit_order` AS `sort` ' +
|
|
|
+ 'FROM ?? AS la LEFT JOIN ?? AS pa ON la.audit_id = pa.id ' +
|
|
|
+ 'WHERE la.vid = ? AND la.times = ? ORDER BY la.`order`, la.id';
|
|
|
+ const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, vid, times];
|
|
|
const result = await this.db.query(sql, sqlParam);
|
|
|
- const sql2 = 'SELECT COUNT(a.`audit_id`) as num FROM (SELECT `audit_id` FROM ?? WHERE `vid` = ? AND `times` = ? GROUP BY `audit_id`) as a';
|
|
|
+ const sql2 = 'SELECT MAX(audit_order) AS num FROM ?? WHERE vid = ? AND times = ?';
|
|
|
const sqlParam2 = [this.tableName, vid, times];
|
|
|
const count = await this.db.queryOne(sql2, sqlParam2);
|
|
|
for (const i in result) {
|
|
|
@@ -200,7 +215,7 @@ module.exports = app => {
|
|
|
*/
|
|
|
async getAuditor(vid, audit_id, times = 1) {
|
|
|
const sql =
|
|
|
- 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`order`, la.`status`, la.`opinion`, la.`create_time`, la.`end_time` ' +
|
|
|
+ 'SELECT la.`audit_id`, pa.`name`, pa.`company`, pa.`role`, pa.`mobile`, pa.`telephone`, la.`times`, la.`audit_order`, la.`audit_type`, la.`order`, la.`status`, la.`opinion`, la.`create_time`, la.`end_time` ' +
|
|
|
' FROM ?? AS la Left Join ?? AS pa On la.`audit_id` = pa.`id` ' +
|
|
|
' WHERE la.`vid` = ? and la.`audit_id` = ? and la.`times` = ?';
|
|
|
const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, vid, audit_id, times];
|
|
|
@@ -214,6 +229,7 @@ module.exports = app => {
|
|
|
* @param {Object} data - 载荷
|
|
|
*/
|
|
|
async start(vid, times = 1, data) {
|
|
|
+ await this.checkAuditNodes(vid, times);
|
|
|
const audit = await this.getDataByCondition({ vid, times, order: 1 });
|
|
|
if (!audit) {
|
|
|
if(this.ctx.tender.info.shenpi.advance === shenpiConst.sp_status.gdspl) {
|
|
|
@@ -367,15 +383,15 @@ module.exports = app => {
|
|
|
if (!audit) {
|
|
|
throw '审核数据错误';
|
|
|
}
|
|
|
- const sql = 'SELECT `tid`, `vid`, `audit_id`, `order` FROM ?? WHERE `vid` = ? and `times` = ? GROUP BY `audit_id` ORDER BY `id` ASC';
|
|
|
+ // 按流程节点去重,保留节点序号和审批类型;退回、重审产生的过程记录不重复复制。
|
|
|
+ const sql = 'SELECT `tid`, `vid`, `type`, `audit_id`, `audit_order`, `audit_type` FROM ?? WHERE `vid` = ? and `times` = ? ' +
|
|
|
+ 'GROUP BY `tid`, `vid`, `type`, `audit_id`, `audit_order`, `audit_type` ORDER BY `audit_order` ASC';
|
|
|
const sqlParam = [this.tableName, advanceId, times];
|
|
|
const auditors = await this.db.query(sql, sqlParam);
|
|
|
- let order = 1;
|
|
|
for (const a of auditors) {
|
|
|
a.times = times + 1;
|
|
|
- a.order = order;
|
|
|
+ a.order = a.audit_order;
|
|
|
a.status = auditConst.status.uncheck;
|
|
|
- order++;
|
|
|
}
|
|
|
const transaction = await this.db.beginTransaction();
|
|
|
try {
|
|
|
@@ -425,7 +441,7 @@ module.exports = app => {
|
|
|
const time = new Date();
|
|
|
// 整理当前流程审核人状态更新
|
|
|
const audit = await this.getDataByCondition({ vid: advanceId, times, status: auditConst.status.checking });
|
|
|
- if (!audit || audit.order <= 1) {
|
|
|
+ if (!audit || audit.audit_order <= 1) {
|
|
|
throw '审核数据错误';
|
|
|
}
|
|
|
// 添加重新审批后,不能用order-1,取groupby值里的上一个才对
|
|
|
@@ -448,6 +464,7 @@ module.exports = app => {
|
|
|
// 顺移气候审核人流程顺序
|
|
|
this.initSqlBuilder();
|
|
|
this.sqlBuilder.setAndWhere('vid', { value: advanceId, operate: '=' });
|
|
|
+ this.sqlBuilder.setAndWhere('times', { value: times, operate: '=' });
|
|
|
this.sqlBuilder.setAndWhere('order', { value: audit.order, operate: '>' });
|
|
|
this.sqlBuilder.setUpdateData('order', { value: 2, selfOperate: '+' });
|
|
|
const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
|
|
|
@@ -459,6 +476,8 @@ module.exports = app => {
|
|
|
audit_id: preAuditor.audit_id,
|
|
|
times: audit.times,
|
|
|
order: audit.order + 1,
|
|
|
+ audit_order: preAuditor.audit_order,
|
|
|
+ audit_type: preAuditor.audit_type,
|
|
|
status: auditConst.status.checking,
|
|
|
create_time: time,
|
|
|
};
|
|
|
@@ -470,6 +489,8 @@ module.exports = app => {
|
|
|
audit_id: audit.audit_id,
|
|
|
times: audit.times,
|
|
|
order: audit.order + 2,
|
|
|
+ audit_order: audit.audit_order,
|
|
|
+ audit_type: audit.audit_type,
|
|
|
status: auditConst.status.uncheck,
|
|
|
};
|
|
|
await transaction.insert(this.tableName, uncheckNewAuditors);
|
|
|
@@ -514,6 +535,7 @@ module.exports = app => {
|
|
|
* @return {Promise<void>}
|
|
|
*/
|
|
|
async check(advanceId, checkData, times = 1, type) {
|
|
|
+ await this.checkAuditNodes(advanceId, times);
|
|
|
if (checkData.checkType !== auditConst.status.checked && checkData.checkType !== auditConst.status.checkNo && checkData.checkType !== auditConst.status.checkNoPre) {
|
|
|
throw '提交数据错误';
|
|
|
}
|
|
|
@@ -539,6 +561,7 @@ module.exports = app => {
|
|
|
* @return {Promise<*>} - 可用的变更令列表
|
|
|
*/
|
|
|
async checkAgain(advance) {
|
|
|
+ await this.checkAuditNodes(advance.id, advance.times);
|
|
|
const accountId = this.ctx.session.sessionUser.accountId;
|
|
|
// 初始化事务
|
|
|
const time = new Date();
|
|
|
@@ -556,6 +579,7 @@ module.exports = app => {
|
|
|
checkAgainAuditors.push({
|
|
|
tid: advance.tid, vid: advance.id, audit_id: x.audit_id, type: advance.type,
|
|
|
times: x.times, order: maxOrder + 1,
|
|
|
+ audit_order: x.audit_order, audit_type: x.audit_type,
|
|
|
status: auditConst.status.checkAgain,
|
|
|
create_time: time, end_time: time, opinion: '',
|
|
|
});
|
|
|
@@ -565,6 +589,7 @@ module.exports = app => {
|
|
|
checkingAuditors.push({
|
|
|
tid: advance.tid, vid: advance.id, audit_id: x.audit_id, type: advance.type,
|
|
|
times: x.times, order: maxOrder + 2,
|
|
|
+ audit_order: x.audit_order, audit_type: x.audit_type,
|
|
|
status: auditConst.status.checking,
|
|
|
create_time: time,
|
|
|
});
|
|
|
@@ -748,6 +773,7 @@ module.exports = app => {
|
|
|
newAuditors.push({
|
|
|
tid: advance.tid, vid: advance.id, type: advance.type, audit_id: aid,
|
|
|
times: advance.times, order, status: auditConst.status.uncheck,
|
|
|
+ audit_order: order, audit_type: auditType.key.common,
|
|
|
});
|
|
|
order++;
|
|
|
}
|
|
|
@@ -769,7 +795,7 @@ module.exports = app => {
|
|
|
await transaction.delete(this.tableName, { vid: advance.id, times: advance.times, audit_id: lastId });
|
|
|
const audit = this._.find(auditList, { 'audit_id': lastId });
|
|
|
// 顺移之后审核人流程顺序
|
|
|
- await this._syncOrderByDelete(transaction, advance.id, audit.order, advance.times);
|
|
|
+ await this._syncOrderByDelete(transaction, advance.id, audit.order, advance.times, '-', audit.audit_order);
|
|
|
order = order - 1;
|
|
|
}
|
|
|
|
|
|
@@ -777,6 +803,7 @@ module.exports = app => {
|
|
|
const newAuditor = {
|
|
|
tid: advance.tid, vid: advance.id, type: advance.type, audit_id: lastId,
|
|
|
times: advance.times, order, status: auditConst.status.uncheck,
|
|
|
+ audit_order: order, audit_type: auditType.key.common,
|
|
|
};
|
|
|
await transaction.insert(this.tableName, newAuditor);
|
|
|
await transaction.commit();
|
|
|
@@ -791,13 +818,7 @@ module.exports = app => {
|
|
|
*/
|
|
|
async getAdminAuditGroups(vid, times) {
|
|
|
const ownerAndAuditors = await this.getAuditorsWithOwner(vid, times);
|
|
|
- const owner = ownerAndAuditors[0];
|
|
|
- const auditors = [owner].concat(await this.getAuditors(vid, times));
|
|
|
- return auditors.map((item, index) => [{
|
|
|
- ...item,
|
|
|
- audit_type: auditType.key.common,
|
|
|
- audit_order: index,
|
|
|
- }]);
|
|
|
+ return ownerAndAuditors.map(item => [item]);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -810,12 +831,20 @@ module.exports = app => {
|
|
|
where: { vid: advance.id, times: advance.times },
|
|
|
orders: [['order', 'asc'], ['id', 'asc']],
|
|
|
});
|
|
|
- const current = audits.find(item => item.audit_id === Number(data.old_aid));
|
|
|
+ const current = audits.slice().reverse().find(item => item.audit_id === Number(data.old_aid));
|
|
|
if (!current) throw '审批人不存在';
|
|
|
+ if (audits.some(x => !(x.audit_order > 0) || x.audit_type !== auditType.key.common)) {
|
|
|
+ throw '请先回填当前预付款的审批节点序号和普通审批类型';
|
|
|
+ }
|
|
|
+ if (data.operate !== 'add' && audits.some(x => x.id !== current.id && x.audit_order === current.audit_order)) {
|
|
|
+ throw '该节点已有历史审批记录,无法移除或更换';
|
|
|
+ }
|
|
|
|
|
|
if (data.operate !== 'del') {
|
|
|
const newId = Number(data.new_aid);
|
|
|
if (!newId) throw '请选择审批人';
|
|
|
+ if (newId === Number(advance.uid)) throw '原报人不能添加为审批人';
|
|
|
+ if (data.operate === 'add' && newId === current.audit_id) throw '该审核人已存在,请勿重复添加';
|
|
|
if (audits.some(item => item.audit_id === newId && item.id !== current.id)) {
|
|
|
throw '该审核人已存在,请勿重复添加';
|
|
|
}
|
|
|
@@ -826,7 +855,7 @@ module.exports = app => {
|
|
|
|
|
|
if (data.operate === 'add') {
|
|
|
if ([auditConst.status.uncheck, auditConst.status.checking].indexOf(current.status) < 0) throw '当前节点后无法新增';
|
|
|
- await this._syncOrderByDelete(transaction, advance.id, current.order + 1, advance.times, '+');
|
|
|
+ await this._syncOrderByDelete(transaction, advance.id, current.order + 1, advance.times, '+', current.audit_order + 1);
|
|
|
await transaction.insert(this.tableName, {
|
|
|
tid: advance.tid,
|
|
|
vid: advance.id,
|
|
|
@@ -834,6 +863,8 @@ module.exports = app => {
|
|
|
audit_id: newId,
|
|
|
times: advance.times,
|
|
|
order: current.order + 1,
|
|
|
+ audit_order: current.audit_order + 1,
|
|
|
+ audit_type: auditType.key.common,
|
|
|
status: auditConst.status.uncheck,
|
|
|
});
|
|
|
} else if (data.operate === 'change') {
|
|
|
@@ -845,20 +876,21 @@ module.exports = app => {
|
|
|
} else {
|
|
|
if (current.status !== auditConst.status.uncheck) throw '当前审批人无法移除';
|
|
|
await transaction.delete(this.tableName, { id: current.id });
|
|
|
- await this._syncOrderByDelete(transaction, advance.id, current.order + 1, advance.times);
|
|
|
+ await this._syncOrderByDelete(transaction, advance.id, current.order + 1, advance.times, '-', current.audit_order + 1);
|
|
|
}
|
|
|
|
|
|
// 同步固定审批配置,避免中间件再次用旧配置覆盖本次调整。
|
|
|
const shenpiStatus = this.ctx.tender.info.shenpi.advance;
|
|
|
- const newAudits = await transaction.select(this.tableName, {
|
|
|
+ const allNewAudits = await transaction.select(this.tableName, {
|
|
|
where: { vid: advance.id, times: advance.times },
|
|
|
- orders: [['order', 'asc'], ['id', 'asc']],
|
|
|
+ orders: [['audit_order', 'asc'], ['order', 'desc']],
|
|
|
});
|
|
|
+ const newAudits = this._.uniqBy(allNewAudits, 'audit_order');
|
|
|
if (shenpiStatus === shenpiConst.sp_status.gdspl) {
|
|
|
- const groups = newAudits.map((item, index) => [{
|
|
|
+ const groups = newAudits.map(item => [{
|
|
|
...item,
|
|
|
audit_type: auditType.key.common,
|
|
|
- audit_order: index + 1,
|
|
|
+ audit_order: item.audit_order,
|
|
|
}]);
|
|
|
await this.ctx.service.shenpiAudit.updateAuditListWithAuditType(
|
|
|
transaction, this.ctx.tender.id, shenpiStatus, shenpiConst.sp_type.advance, groups, advance.sp_group || 0
|