Просмотр исходного кода

1. 协同,审批通过锁定相关
2. 台账修订,排序调整

MaiXinRong 9 часов назад
Родитель
Сommit
c11d521cc8

+ 10 - 15
app/controller/stage_controller.js

@@ -429,13 +429,12 @@ module.exports = app => {
                                 responseData.data.ledgerData = await this._getStageLedgerData(ctx);
                             }
                             const assistLocked = await ctx.service.stageAuditAss.getLockedId(ctx.stage);
-                            const auditLocked = await ctx.service.stageAudit.getLockedId(ctx.stage);
-                            responseData.data.locked = [...assistLocked, ...auditLocked];
+                            const auditUnionLocked = await ctx.service.stageAudit.getUnionLockedId(ctx.stage);
+                            const auditLocked = await ctx.service.stageAudit.getAuditLockedId(ctx.stage);
+                            responseData.data.locked = [...assistLocked, ...auditUnionLocked, ...auditLocked];
                             if (ctx.tender.info.fun_rela.repel && !ctx.stage.readOnly) {
                                 const assistComfirm = await ctx.service.stageAuditAss.getComfirmLockedId(ctx.stage);
-                                const auditComfirm = ctx.stage.curAuditors && ctx.stage.curAuditors.length > 0 && ctx.stage.curAuditors[0].audit_type === auditType.key.union
-                                    ? await ctx.service.stageAuditAss.getComfirmLockedId(ctx.stage) : [];
-                                responseData.data.locked.push(...assistComfirm, ...auditComfirm);
+                                responseData.data.locked.push(...assistComfirm);
                             }
                             break;
                         case 'pos':
@@ -1492,8 +1491,8 @@ module.exports = app => {
                 }
 
                 await ctx.service.stageAudit.start(ctx.stage.id, ctx.stage.times);
-                const rstMsg = await ctx.service.roleRptRel.refreshSignatureDate(ctx.tender.data.id, ctx.stage.id, 'stage', -1, [ctx.stage.user_id]);
-                // console.log(rstMsg);
+                await ctx.service.roleRptRel.refreshSignatureDate(ctx.tender.data.id, ctx.stage.id, 'stage', -1, [ctx.stage.user_id]);
+                await ctx.service.stageAudit.checkAuditSkip(ctx.stage.id);
                 ctx.body = { err: 0, msg: '', data: [] };
             } catch (err) {
                 this.log(err);
@@ -1528,8 +1527,8 @@ module.exports = app => {
 
                 await ctx.service.stageAudit.check(ctx.stage.id, data, ctx.stage.times);
                 // // 这里要调用签名的service,重设签名日期
-                const rstMsg = await ctx.service.roleRptRel.refreshSignatureDate(ctx.tender.data.id, ctx.stage.id, 'stage', -1, [ctx.session.sessionUser.accountId]);
-                // console.log(rstMsg);
+                await ctx.service.roleRptRel.refreshSignatureDate(ctx.tender.data.id, ctx.stage.id, 'stage', -1, [ctx.session.sessionUser.accountId]);
+                await ctx.service.stageAudit.checkAuditSkip(ctx.stage.id);
                 ctx.body = { err: 0, msg: '', data: [] };
             } catch (err) {
                 this.log(err);
@@ -1569,9 +1568,8 @@ module.exports = app => {
 
                 if ((ctx.stage.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) >= 0 || (ctx.query.confirm === '确认设置终审审批' && ctx.session.sessionUser.is_admin)) && ctx.stage.status === auditConst.status.checked && ctx.stage.order === ctx.stage.highOrder) {
                     await ctx.service.stageAudit.checkAgain(ctx.stage.id, ctx.stage.times, (ctx.query.confirm === '确认设置终审审批' && ctx.session.sessionUser.is_admin));
-                    // ctx.redirect(ctx.request.header.referer);
-                    const rstMsg = await ctx.service.roleRptRel.refreshSignatureDate(ctx.tender.data.id, ctx.stage.id, 'stage', -1, [ctx.session.sessionUser.accountId]);
-                    // console.log(rstMsg);
+                    await ctx.service.roleRptRel.refreshSignatureDate(ctx.tender.data.id, ctx.stage.id, 'stage', -1, [ctx.session.sessionUser.accountId]);
+                    await ctx.service.stageAudit.checkAuditSkip(ctx.stage.id);
                     ctx.body = {
                         err: 0,
                         url: ctx.request.header.referer,
@@ -1582,11 +1580,8 @@ module.exports = app => {
                 }
             } catch (err) {
                 this.log(err);
-                // ctx.session.postError = err.toString();
-                // ctx.redirect(ctx.request.header.referer);
                 ctx.body = {
                     err: 1,
-                    // url: ctx.request.header.referer,
                     msg: err,
                 };
             }

+ 18 - 0
app/lib/ledger.js

@@ -429,6 +429,24 @@ class billsTree extends baseTree {
         }
         return null;
     }
+    checkUsed(node, fields) {
+        if (!node) return false;
+        const checkNodes = node.children && node.children.length > 0 ? this.getPosterity(node) : [node];
+        for (const cn of checkNodes) {
+            if (cn.children && cn.children.length > 0) continue;
+            for (const f of fields) {
+                if (cn[f]) return true;
+            }
+        }
+        return false;
+    }
+    checkNodesUsed(nodes, fields) {
+        if (!nodes || nodes.length === 0) return false;
+        for (const n of nodes) {
+            if (this.checkUsed(n, fields)) return true;
+        }
+        return false;
+    }
 }
 
 class filterTree extends baseTree {

+ 2 - 1
app/public/js/path_tree.js

@@ -1443,7 +1443,8 @@ const createNewPathTree = function (type, setting) {
         _loadLockedNodes(ids){
             this.Locked = ids || [];
             for (const f of this.Locked) {
-                f.locked_ledger_id = f.ass_ledger_id ? f.ass_ledger_id.split(',') : (f.audit_ledger_id ? f.audit_ledger_id.split(',') : []);
+                const lockedId = f.ass_ledger_id || f.audit_locked_lid || f.audit_ledger_id;
+                f.locked_ledger_id = lockedId ? lockedId.split(',') : [];
                 for (const id of f.locked_ledger_id) {
                     const node = this.getItems(id);
                     if (!node) continue;

+ 17 - 12
app/public/js/shares/gcl_gather_compare.js

@@ -421,22 +421,27 @@ const gclCompareModel = (function () {
             return -1;
         }
 
+        const numReg = /^[0-9]+$/;
+        const hasNumReg = /[0-9]+$/;
+        const splitNumReg = /\d+|[^\d]+/g;
         function compareSubCode(code1, code2) {
-            if (numReg.test(code1)) {
-                if (numReg.test(code2)) {
-                    return parseInt(code1) - parseInt(code2);
-                } else {
-                    return -1
-                }
-            } else {
-                if (numReg.test(code2)) {
-                    return 1;
-                } else {
-                    return code1 === code2 ? 0 : (code1 < code2 ? -1 : 1); //code1.localeCompare(code2);
+            if (numReg.test(code1)) return numReg.test(code2) ? parseInt(code1) - parseInt(code2) : -1;
+            if (numReg.test(code2)) return 1;
+            if (hasNumReg.test(code1) && hasNumReg.test(code2)) {
+                const parts1 = code1.match(splitNumReg);
+                const parts2 = code2.match(splitNumReg);
+                for (let i = 0, iLen = Math.min(parts1.length, parts2.length); i < iLen; i++) {
+                    if (parts1[i] === parts2[i]) continue;
+                    if (numReg.test(parts1[i])) {
+                        return numReg.test(parts2[i]) ? parseInt(parts1[i]) - parseInt(parts2[i]) : -1;
+                    } else {
+                        return (parts1[i] < parts2[i] ? -1 : 1)
+                    }
                 }
+                return parts1.length - parts2.length;
             }
+            return code1 === code2 ? 0 : (code1 < code2 ? -1 : 1); //code1.localeCompare(code2);
         }
-        const numReg = /^[0-9]+$/;
         const aCodes = str1.split(symbol), bCodes = str2.split(symbol);
         for (let i = 0, iLength = Math.min(aCodes.length, bCodes.length); i < iLength; ++i) {
             const iCompare = compareSubCode(aCodes[i], bCodes[i]);

+ 4 - 1
app/service/stage.js

@@ -246,7 +246,10 @@ module.exports = app => {
             if (stage.status !== status.checked && stage.status !== status.uncheck) {
                 if (stage.status !== status.checkNo) {
                     // 找出当前操作人上一个审批人,包括审批完成的和退回上一个审批人的,同时当前操作人为第一人时,就是则为原报
-                    if (stage.flowAuditors.find(x => { return x.status !== auditConst.stage.status.checking}) && stage.flowAuditorIds.indexOf(accountId) < 0) return; // 当前流程存在审批人审批通过时,不可撤回
+                    // 当前流程存在审批人 主动进行任何审批操作时,不可撤回
+                    if (stage.flowAuditors.find(x => { return x.status !== auditConst.stage.status.checking && x.status !== auditConst.stage.status.checkSkip; })
+                        && stage.flowAuditorIds.indexOf(accountId) < 0) return;
+
                     const flowAssists = stage.auditAssists.filter(x => { return stage.flowAuditorIds.indexOf(x.user_id) >= 0; });
                     if (flowAssists.find(x => { return x.confirm; })) return; //当前流程存在协审人确认时,不可撤回
                     if (stage.curAuditorIds.indexOf(accountId) < 0 && stage.flowAuditorIds.indexOf(accountId) >= 0) {

+ 63 - 99
app/service/stage_audit.js

@@ -328,7 +328,7 @@ module.exports = app => {
             try {
                 const ledgerTp = await this._updateTender(transaction);
                 const begin_time = new Date();
-                const updateData = audits.map(x => { return { id: x.id, status: auditConst.status.checking, begin_time } });
+                const updateData = audits.map(x => { return { id: x.id, status: auditConst.status.checking, begin_time, audit_locked: 0 } });
                 await transaction.updateRows(this.tableName, updateData);
                 // 计算原报最终数据
                 const [yfPay, sfPay] = await this.ctx.service.stagePay.calcAllStagePays(this.ctx.stage, transaction);
@@ -513,7 +513,12 @@ module.exports = app => {
                         await this.ctx.service.stageSafeProd.updateHistory(this.ctx.stage, transaction);
                         await this.ctx.service.stageTempLand.updateHistory(this.ctx.stage, transaction);
                         // 流程至下一审批人
-                        const updateData = nextAudits.map(x => { return { id: x.id, status: auditConst.status.checking, begin_time: time }; });
+                        const updateData = nextAudits.map(x => {
+                            return {
+                                id: x.id, status: x.audit_locked ? auditConst.status.checking : x.status,
+                                begin_time: x.audit_locked ? x.begin_time : time, audit_locked: 0,
+                            };
+                        });
                         await transaction.updateRows(this.tableName, updateData);
                         // 同步 期信息
                         await transaction.update(this.ctx.service.stage.tableName, {
@@ -658,15 +663,18 @@ module.exports = app => {
             const tpData = await this.ctx.service.stageBills.getSumTotalPrice(this.ctx.stage);
             const auditors = await this.getUniqAuditor(stageId, times); // 全部参与的审批人
             const newAuditors = auditors.map(x => {
-               return {
-                   aid: x.aid, tid: selfAudit.tid, sid: selfAudit.sid,
-                   times: times + 1, order: x.audit_order, status: auditConst.status.uncheck,
-                   audit_type: x.audit_type, audit_order: x.audit_order,
-                   audit_group: x.audit_group, audit_group_order: x.audit_group_order,
-                   audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
-                   audit_group_need: x.audit_group_need,
-                   audit_ledger_id: x.audit_ledger_id,
-               }
+                const locked = x.audit_locked || (x.audit_type === auditType.key.union && x.status === auditConst.status.checked && x.audit_order === selfAudit.audit_order) ? 1 : 0;
+                return {
+                    aid: x.aid, tid: selfAudit.tid, sid: selfAudit.sid,
+                    times: times + 1, order: x.audit_order, status: locked ? x.status : auditConst.status.uncheck,
+                    begin_time: locked ? x.begin_time : null, end_time: locked ? x.end_time: null,
+                    audit_type: x.audit_type, audit_order: x.audit_order,
+                    audit_group: x.audit_group, audit_group_order: x.audit_group_order,
+                    audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
+                    audit_group_need: x.audit_group_need,
+                    audit_ledger_id: x.audit_ledger_id,
+                    audit_locked: locked,
+                }
             });
 
             const transaction = await this.db.beginTransaction();
@@ -890,15 +898,18 @@ module.exports = app => {
                 }
                 const newFlowAuditors = [];
                 flowAudits.forEach(x => {
+                    const locked = x.audit_type === auditType.key.union && x.status === auditConst.status.checked ? 1 : 0;
                     newFlowAuditors.push({
                         tid: this.ctx.stage.tid, sid: this.ctx.stage.id, aid: x.aid,
                         times: x.times, order: selfAudit.order + 2,
-                        status: auditConst.status.uncheck,
+                        status: locked ? auditConst.status.checked : auditConst.status.uncheck,
                         audit_type: x.audit_type, audit_order: x.audit_order,
                         audit_group: x.audit_group, audit_group_order: x.audit_group_order,
                         audit_group_limit: x.audit_group_limit, audit_checkno_valid: x.audit_checkno_valid,
                         audit_group_need: x.audit_group_need,
                         audit_ledger_id: x.audit_ledger_id,
+                        audit_locked: locked,
+                        begin_time: locked ? x.begin_time : null, end_time: locked ? x.end_time : null,
                     });
                 });
                 await transaction.insert(this.tableName, newFlowAuditors);
@@ -2368,96 +2379,12 @@ module.exports = app => {
             return result;
         }
 
-        async lockConfirm4CheckNoPre(stage, uid, pre_uid, transaction) {
-            if (!transaction) throw '缺少参数';
-
-            const locked = await this.getAllDataByCondition({ where: { sid: stage.id, locked: 1, times: stage.curTimes } });
-            locked.forEach(x => {
-                x.locked_ledger_id = x.ass_ledger_id.split(',');
-            });
-            // 审批人数据锁定
-            const locking = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, user_id: uid, confirm: 1 } });
-            locking.forEach(x => {
-                x.locked_ledger_id = x.ass_ledger_id.split(',');
-            });
-            if (locking.length > 0) {
-                const updateLock = locking.map(x => { return { id: x.id, locked: 1 }; });
-                await transaction.updateRows(this.tableName, updateLock);
-            }
-            const preConfirm = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, user_id: pre_uid, confirm: 1 } });
-            // 前审批人数据,与被锁定数据相关数据确认状态保留
-            locked.push(...locking);
-            if (preConfirm.length > 0) {
-                const delConfirm = [];
-                for (const pc of preConfirm) {
-                    const bills = await this.ctx.service.ledger.getDataByCondition({ tender_id: stage.tid, ledger_id: pc.ledger_id });
-                    const billsOwner = bills ? bills.full_path.split('-') : [];
-                    const exist = locked.find(x => {
-                        for (const id of x.locked_ledger_id) {
-                            if (billsOwner.indexOf(id) >= 0) return true;
-                        }
-                        return false;
-                    });
-                    if (!exist) delConfirm.push(pc.id);
-                }
-                if (delConfirm.length > 0) await transaction.delete(this.tableName, { id: delConfirm });
-            }
-        }
-
-        async lockConfirm4CheckNo(stage, uid, auditors, transaction) {
-            if (!transaction) throw '缺少参数';
-            // 审批人数据锁定
-            const lockConfirm = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, o: uid, confirm: 1 } });
-            if (lockConfirm.length === 0) return;
-
-            const insertData = [];
-            lockConfirm.forEach(x => {
-                delete x.id;
-                x.locked = 1;
-                x.times = x.times + 1;
-                insertData.push(x);
-            });
-            // 审批人前所有角色,与锁定数据相关确认状态保留
-            const keepUid = [ stage.user_id ];
-            for (const a of auditors) {
-                if (a.aid === uid) break;
-                keepUid.push(a.aid);
-            }
-            const keepConfirm = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.curTimes, user_id: keepUid, confirm: 1 } });
-            for (const kc of keepConfirm) {
-                const bills = await this.ctx.service.ledger.getDataByCondition({ tender_id: stage.tid, ledger_id: kc.ledger_id });
-                const billsOwner = bills ? bills.full_path.split('-') : [];
-                const exist = lockConfirm.find(x => {
-                    const lid = x.ass_ledger_id.split(',');
-                    for (const id of lid) {
-                        if (billsOwner.indexOf(id) >= 0) return true;
-                    }
-                    return false;
-                });
-                if (exist) {
-                    delete kc.id;
-                    kc.locked = 0;
-                    kc.times = kc.times + 1;
-                    insertData.push(kc);
-                }
-            }
-            if (insertData.length > 0) await transaction.insert(this.tableName, insertData);
-        }
-
-        async cancelLock(stage, uid, transaction) {
-            if (transaction) {
-                await transaction.update(this.tableName, { locked: 0 }, { where: { sid: stage.id, times: stage.times, aid: uid } });
-            } else {
-                await this.db.update(this.tableName, { locked: 0 }, { where: { sid: stage.id, times: stage.times, aid: uid } });
-            }
-        }
-
-        async getLockedId(stage) {
+        async getUnionLockedId(stage) {
             return await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.times, audit_locked: 1 } });
         }
 
-        async getComfirmLockedId(stage) {
-            return await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.times, order: stage.curOrder, status: auditConst.status.checked } });
+        async getAuditLockedId(stage) {
+            return await this.db.query(`SELECT * FROM ${this.tableName} where sid = ? and times = ? and audit_locked_lid <> ''`, [stage.id, stage.times]);
         }
 
         /**
@@ -2502,6 +2429,43 @@ module.exports = app => {
             }
             return true;
         }
+
+        async checkAuditSkip(sid) {
+            const stage = await this.ctx.service.stage.getDataById(sid);
+            if (stage.status === auditConst.status.checked) return;
+            if (stage.status === auditConst.status.uncheck || stage.status === auditConst.status.checkNo) return;
+
+            await this.service.stage.doCheckStage(stage, true);
+            if (!stage.curAuditors || stage.curAuditors[0].audit_type !== auditType.key.union) return;
+
+            const ledgerData = await this.ctx.service.ledger.getData(stage.tid);
+            const curStageData = await this.ctx.service.stageBills.getLastestStageData2(stage.tid, stage.id);
+            const checkCalcFields = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty'];
+            this.ctx.helper.assignRelaData(ledgerData, [
+                { data: curStageData, fields: checkCalcFields, prefix: '', relaId: 'lid' },
+            ]);
+            const Ledger = require('../lib/ledger');
+            const billsTree = new Ledger.billsTree(this.ctx, {
+                id: 'ledger_id',
+                pid: 'ledger_pid',
+                order: 'order',
+                level: 'level',
+                rootId: -1,
+                calcFields: []
+            });
+            billsTree.loadDatas(ledgerData);
+
+            const curTime = new Date();
+            const skipAudit = [];
+            for (const audit of stage.curAuditors) {
+                const auditNodes = audit.audit_ledger_id.split(',').map(x => { return billsTree.getItems(parseInt(x))});
+                if (billsTree.checkNodesUsed(auditNodes, checkCalcFields)) {
+                    skipAudit.push({ id: audit.id, status: auditConst.status.checkSkip, opinion: '协同节点未计量', end_time: curTime });
+                }
+            }
+            if (skipAudit.length === stage.curAuditors.length) skipAudit.pop();
+            if (skipAudit.length > 0) await this.db.updateRows(this.tableName, skipAudit);
+        }
     }
 
     return StageAudit;

+ 3 - 0
sql/update.sql

@@ -39,6 +39,9 @@ ALTER TABLE `zh_contract_pay`
 ADD COLUMN `kp_price` decimal(30, 8) NULL DEFAULT 0 COMMENT '开票金额' AFTER `pay_type`,
 ADD COLUMN `kp_time` datetime NULL DEFAULT NULL COMMENT '开票时间' AFTER `kp_price`;
 
+ALTER TABLE `zh_stage_audit`
+ADD COLUMN `audit_locked_lid` varchar(5000) NOT NULL DEFAULT '' COMMENT '审批退回锁定台账id' AFTER `audit_locked`;
+
 ------------------------------------
 -- 表数据
 ------------------------------------