| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 | 'use strict';/** * * * @author Mai * @date * @version */const auditConst = require('../const/audit');const projectLogConst = require('../const/project_log');const shenpiConst = require('../const/shenpi');const settleStatus = [    { key: 'non', value: 0, name: '未结算', short: '', color: '' },    { key: 'part', value: 1, name: '部分结算', short: '部分', color: '#da9500' },    { key: 'finish', value: 2, name: '已结算', short: '结', color: '#28a745' },];module.exports = app => {    class Settle extends app.BaseService {        /**         * 构造函数         *         * @param {Object} ctx - egg全局变量         * @return {void}         */        constructor(ctx) {            super(ctx);            this.tableName = 'settle';        }        get statusArray() {            if (!this._statusArray) {                const arr = [];                settleStatus.forEach(x => { arr[x.value] = x.short; });                this._statusArray = arr;            }            return this._statusArray;        }        get statusColor() {            if (!this._statusColor) {                const arr = [];                settleStatus.forEach(x => { arr[x.value] = x.color; });                this._statusColor = arr;            }            return this._statusColor;        }        get settleStatus() {            if (!this._settleStatus) {                const status = {};                settleStatus.forEach(x => { status[x.key] = x.value; });                this._settleStatus = status;            }            return this._settleStatus;        }        /**         * 获取标段下的全部结算期,按倒序         * @param tenderId         * @return {Promise<void>}         */        async getValidSettles(tenderId) {            const settles = await this.db.select(this.tableName, {                where: { tid: tenderId },                orders: [['settle_order', 'desc']],            });            if (settles.length !== 0 && !this.ctx.session.sessionUser.is_admin) {                const last = settles[0];                if (last.audit_status === auditConst.settle.status.uncheck && !this.ctx.tender.isTourist) {                    if (last.user_id !== this.ctx.session.sessionUser.accountId) {                        settles.splice(0, 1);                    }                }            }            return settles;        }        async getLatestCompleteSettle(tenderId) {            const settles = await this.getAllDataByCondition({                where: { tid: tenderId, audit_status: auditConst.settle.status.checked },                order: [['settle_order', 'desc']],                limit: 1, offset: 0            });            return settles[0];        }        async getReadySettle(tenderId) {            const settles = await this.db.select(this.tableName, {                where: { tid: tenderId },                orders: [['settle_order', 'desc']],            });            if (settles.length === 0) return null;            if (settles[0].audit_status !== auditConst.settle.status.uncheck && settles[0].audit_status !== auditConst.settle.status.checkNo) return settles[0];            return settles.length > 1 ? settles[1] : null;        }        /**         * 新增结算期         * @param tenderId - 标段id         * @param date - 结算年月         * @param period - 结算周期         * @return {Promise<void>}         */        async addSettle(tenderId, date, period) {            const settles = await this.getAllDataByCondition({                where: { tid: tenderId },                orders: [['settle_order', 'asc']],            });            const pre = settles[settles.length - 1];            if (settles.length > 0 && pre.audit_status !== auditConst.settle.status.checked) {                throw '上一期未审批通过,请等待上一期审批通过后,再新增数据';            }            const checkedStage = await this.ctx.service.stage.getLastestCompleteStage(tenderId);            if (!checkedStage) throw '不存在审批通过的计量期,请先进行期计量,再结算';            const newSettle = {                tid: tenderId,                add_sid: checkedStage.id, add_sorder: checkedStage.order,                user_id: this.ctx.session.sessionUser.accountId,                settle_order: settles.length + 1, settle_time: date, settle_period: period,                audit_times: 1, audit_status: auditConst.settle.status.uncheck,            };            if (pre) {                newSettle.pre_contract_tp = this.ctx.helper.add(pre.pre_contract_tp, pre.contract_tp);                newSettle.pre_positive_qc_tp = this.ctx.helper.add(pre.pre_positive_qc_tp, pre.positive_qc_tp);                newSettle.pre_negative_qc_tp = this.ctx.helper.add(pre.pre_negative_qc_tp, pre.negative_qc_tp);                newSettle.pre_qc_tp = this.ctx.helper.add(pre.pre_qc_tp, pre.qc_tp);                newSettle.pre_tp = this.ctx.helper.add(pre.tp, pre.pre_tp);            }            const transaction = await this.db.beginTransaction();            try {                // 新增期记录                const result = await transaction.insert(this.tableName, newSettle);                if (result.affectedRows === 1) {                    newSettle.id = result.insertId;                } else {                    throw '新增期数据失败';                }                await this.ctx.service.settleAudit.copyPreAuditors(transaction, pre, newSettle);                // 存在上一期时                if (pre) {                    // todo 复制上一期其他数据                }                await transaction.commit();            } catch (err) {                await transaction.rollback();                throw err;            }            return newSettle;        }        /**         * 编辑结算期         *         * @param {Number} tenderId - 标段Id         * @param {Number} settleOrder - 第N期         * @param {String} date - 结算年月         * @param {String} period - 结算周期         * @return {Promise<void>}         */        async saveSettle(tenderId, settleOrder, date, period) {            await this.db.update(this.tableName, {                settle_time: date,                settle_period: period,            }, { where: { tid: tenderId, settle_order: settleOrder } });        }        /**         * 删除结算期         * @param id         * @returns {Promise<boolean>}         */        async deleteSettle(id) {            const transaction = await this.db.beginTransaction();            try {                const settleInfo = await this.getDataById(id);                await transaction.delete(this.tableName, { id });                await transaction.delete(this.ctx.service.settleAudit.tableName, { settle_id: id });                await transaction.delete(this.ctx.service.settleBills.tableName, { settle_id: id });                await transaction.delete(this.ctx.service.settlePos.tableName, { settle_id: id });                await transaction.delete(this.ctx.service.settleSelect.tableName, { settle_id: id });                // 记录删除日志                await this.ctx.service.projectLog.addProjectLog(transaction, projectLogConst.type.settle, projectLogConst.status.delete, `第${settleInfo.settle_order}期`);                await transaction.commit();                return true;            } catch (err) {                await transaction.rollback();                throw err;            }        }        async loadRelaUser(settle) {            const status = auditConst.settle.status;            const accountId = this.ctx.session.sessionUser.accountId;            settle.user = await this.ctx.service.projectAccount.getAccountInfoById(settle.user_id);            settle.auditors = await this.ctx.service.settleAudit.getAuditors(settle.id, settle.audit_times); // 全部参与的审批人            settle.auditorIds = this._.map(settle.auditors, 'audit_id');            settle.curAuditors = settle.auditors.filter(x => { return x.audit_status === status.checking; }); // 当前流程中审批中的审批人            settle.curAuditorIds = this._.map(settle.curAuditors, 'audit_id');            settle.flowAuditors = settle.curAuditors.length > 0 ? settle.auditors.filter(x => { return x.active_order === settle.curAuditors[0].active_order; }) : []; // 当前流程中参与的审批人(包含会签时,审批通过的人)            settle.flowAuditorIds = this._.map(settle.flowAuditors, 'audit_id');            settle.auditorGroups = this.ctx.helper.groupAuditors(settle.auditors);            settle.userGroups = this.ctx.helper.groupAuditorsUniq(settle.auditorGroups);            settle.finalAuditorIds = settle.userGroups[settle.userGroups.length - 1].map(x => { return x.audit_id; });            // 协作相关            settle.assists = []; //await this.service.settleAuditAss.getData(settle); // 全部协同人            settle.assists = settle.assists.filter(x => {                return x.user_id === settle.user_id || settle.auditorIds.indexOf(x.user_id) >= 0;            }); // 过滤无效协同人            settle.userAssists = settle.assists.filter(x => { return x.user_id === settle.user_id; }); // 原报协同人            settle.userAssistIds = this._.map(settle.userAssists, 'ass_user_id');            settle.auditAssists = settle.assists.filter(x => { return x.user_id !== settle.user_id; }); // 审批协同人            settle.auditAssistIds = this._.map(settle.auditAssists, 'ass_user_id');            settle.curAssists = settle.assists.filter(x => { return settle.curAuditorIds.indexOf(x.user_id) >= 0; }); // 当前审批人的协同人            settle.curAssistsIds = this._.map(settle.curAssists, 'ass_user_id');            settle.relaAssists = settle.assists.filter(x => { return x.user_id === accountId }); // 登录人的协同人            // 当前参与人Id            settle.userIds = settle.audit_status === settle.uncheck // 当前流程下全部参与人id                ? [settle.user_id, ...settle.userAssistIds]                : [settle.user_id, ...settle.userAssistIds, ...settle.auditorIds, ...settle.auditAssistIds];        }        async loadAuditViewData(settle) {            const auditTimes = settle.audit_status === auditConst.settle.status.checkNo ? settle.audit_times - 1 : settle.audit_times;            if (!settle.user) settle.user = await this.ctx.service.projectAccount.getAccountInfoById(settle.user_id);            settle.auditHistory = await this.ctx.service.settleAudit.getAuditorHistory(settle.id, auditTimes);            // 获取审批流程中左边列表            if (settle.audit_status === auditConst.settle.status.checkNo && settle.user_id !== this.ctx.session.sessionUser.accountId) {                const auditors = await this.ctx.service.settleAudit.getAuditors(settle.id, settle.audit_times - 1); // 全部参与的审批人                const auditorGroups = this.ctx.helper.groupAuditors(auditors);                settle.hisUserGroup = this.ctx.helper.groupAuditorsUniq(auditorGroups);            } else {                settle.hisUserGroup = settle.userGroups;            }        }        /**         * cancancel = 0 不可撤回         * cancancel = 1 原报撤回         * cancancel = 2 审批人撤回 审批通过         * cancancel = 3 审批人撤回 审批退回上一人         * cancancel = 4 审批人撤回 退回原报         * cancancel = 5 会签未全部审批通过时,审批人撤回 审批通过         *         * @param settle         * @returns {Promise<void>}         */        async _doCheckSettleCanCancel(settle) {            // 默认不可撤回            settle.cancancel = 0;            // 获取当前审批人的上一个审批人,判断是否是当前登录人,并赋予撤回功能,(当审批人存在有审批过时,上一人不允许再撤回)            const status = auditConst.settle.status;            if (settle.audit_status === status.checked || settle.audit_status === status.uncheck) return;            const accountId = this.ctx.session.sessionUser.accountId;            if (settle.audit_status !== status.checkNo) {                // 找出当前操作人上一个审批人,包括审批完成的和退回上一个审批人的,同时当前操作人为第一人时,就是则为原报                if (settle.flowAuditors.find(x => { return x.audit_status !== status.checking}) && settle.flowAuditorIds.indexOf(accountId) < 0) return; // 当前流程存在审批人审批通过时,不可撤回                const flowAssists = settle.auditAssists.filter(x => { return settle.flowAuditorIds.indexOf(x.user_id) >= 0; });                if (flowAssists.find(x => { return x.confirm; })) return; //当前流程存在协审人确认时,不可撤回                if (settle.curAuditorIds.indexOf(accountId) < 0 && settle.flowAuditorIds.indexOf(accountId) >= 0) {                    settle.cancancel = 5; // 会签未全部审批通过时,审批人撤回审批通过                    return;                }                const preAuditors = settle.curAuditors[0] && settle.curAuditors[0].active_order !== 1 ? settle.auditors.filter(x => { return x.active_order === settle.curAuditors[0].active_order - 1; }) : [];                const preAuditorCheckAgain = preAuditors.find(pa => { return pa.audit_status === status.checkAgain; });                const preAuditorCheckCancel = preAuditors.find(pa => { return pa.audit_status === status.checkCancel; });                const preAuditorHasOld = preAuditors.find(pa => { return pa.is_old === 1; });                const preAuditorIds = (preAuditorCheckAgain ? [] : preAuditors.map(x => { return x.audit_id })); // 重审不可撤回                if ((this._.isEqual(settle.flowAuditorIds, preAuditorIds) && preAuditorCheckCancel) || preAuditorHasOld) {                    return; // 不可以多次撤回                }                const preAuditChecked = preAuditors.find(pa => { return pa.audit_status === status.checked && pa.audit_id === accountId; });                const preAuditCheckNoPre = preAuditors.find(pa => { return pa.audit_status === status.checkNoPre && pa.audit_id === accountId; });                if (preAuditorIds.indexOf(accountId) >= 0) {                    if (preAuditChecked) {                        settle.cancancel = 2;// 审批人撤回审批通过                    } else if (preAuditCheckNoPre) {                        settle.cancancel = 3;// 审批人撤回审批退回上一人                    }                    settle.preAuditors = preAuditors;                } else if (preAuditors.length === 0 && accountId === settle.user_id) {                    settle.cancancel = 1;// 原报撤回                }            } else {                const lastAuditors = await this.ctx.service.settleAudit.getAuditors(settle.id, settle.audit_times - 1);                const onAuditor = this._.findLast(lastAuditors, { audit_status: status.checkNo });                if (onAuditor.audit_id === accountId) {                    settle.cancancel = 4;// 审批人撤回退回原报                    settle.preAuditors = lastAuditors.filter(x => { return x.active_order === onAuditor.active_order });                }            }        }        async _doCheckSettleReadOnly(settle) {            const status = auditConst.settle.status;            // 校验权限(参与人、分享、游客)            const accountId = this.ctx.session.sessionUser.accountId;            const shareIds = [];            // 是否只读            if (settle.audit_status === status.uncheck || settle.audit_status === status.checkNo) {                settle.readOnly = accountId !== settle.user_id && settle.userAssistIds.indexOf(accountId) < 0;            } else {                settle.readOnly = true;            }            // 读取数据相关            settle.curTimes = settle.audit_status === status.checkNo && settle.readOnly ? settle.audit_times - 1 : settle.audit_times;            // 协作人相关            if (settle.audit_status === status.uncheck) {                if (!settle.readOnly) {                    settle.assist = settle.userAssists.find(x => { return x.ass_user_id === accountId; });                }                settle.curTimes = settle.audit_times;            } else if (settle.audit_status === status.checkNo) {                if (!settle.readOnly) {                    settle.assist = settle.userAssists.find(x => { return x.ass_user_id === accountId; });                    settle.curTimes = settle.audit_times;                }            } else {                const ass = settle.auditAssists.find(x => { return settle.flowAuditorIds.indexOf(x.user_id) >= 0 && x.ass_user_id === accountId; });                if (!settle.readOnly) {                    settle.assist = ass;                }                if (!settle.readOnly) {                    settle.readOnly = !this._.isEqual(settle.flowAuditorIds, settle.curAuditorIds);                    settle.canCheck = true;                }            }            if (settle.readOnly) {                settle.assist = accountId === settle.user_id || settle.auditorIds.indexOf(accountId) >= 0 ? null : settle.auditAssists.find(x => { return x.ass_user_id === accountId});            }            // 上传文件权限            const permission = this.ctx.session.sessionUser.permission;            if (settle.userIds.indexOf(accountId) >= 0 || this.ctx.session.sessionUser.is_admin) {                settle.filePermission = true;            } else {                if (shareIds.indexOf(accountId) !== -1 || (permission !== null && permission.tender !== undefined && permission.tender.indexOf('2') !== -1)) {// 分享人                    if (settle.audit_status === status.uncheck) throw '您无权查看该数据';                    settle.filePermission = false;                } else if (this.ctx.tender.isTourist || this.ctx.session.sessionUser.is_admin) {                    settle.filePermission = this.ctx.tender.touristPermission.file || settle.auditorIds.indexOf(accountId) !== -1;                } else {                    throw '您无权查看该数据';                }            }        }        async doCheckSettle(settle) {            // 读取原报、审核人等参与人数据            await this.loadRelaUser(settle);            // 是否只读等权限            await this._doCheckSettleReadOnly(settle);            // 可否撤回,是哪一种撤回            await this._doCheckSettleCanCancel(settle);        }        async checkSettleShenpi(settle) {            const status = auditConst.settle.status;            const info = this.ctx.tender.info;            const shenpi_status = info.shenpi.settle;            if ((settle.audit_status === status.uncheck || settle.audit_status === status.checkNo) && shenpi_status !== shenpiConst.sp_status.sqspr) {                // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审                const auditList = await this.ctx.service.settleAudit.getAllDataByCondition({ where: { settle_id: settle.id, audit_times: settle.audit_times }, orders: [['audit_order', 'asc']] });                auditList.shift();                if (shenpi_status === shenpiConst.sp_status.gdspl) {                    const shenpiList = await this.ctx.service.shenpiAudit.getAllDataByCondition({ where: { tid: settle.tid, sp_type: shenpiConst.sp_type.settle, sp_status: shenpi_status } });                    // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流                    let sameAudit = auditList.length === shenpiList.length;                    if (sameAudit) {                        for (const audit of auditList) {                            const shenpi = shenpiList.find(x => { return x.audit_id === audit.audit_id; });                            if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {                                sameAudit = false;                                break;                            }                        }                    }                    if (!sameAudit) {                        await this.ctx.service.settleAudit.updateNewAuditList(settle, shenpiList);                        await this.loadRelaUser(settle);                    }                } else if (shenpi_status === shenpiConst.sp_status.gdzs) {                    const shenpiInfo = await this.ctx.service.shenpiAudit.getDataByCondition({ tid: settle.tid, sp_type: shenpiConst.sp_type.settle, sp_status: shenpi_status });                    // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审                    const lastAuditors = auditList.filter(x => { x.active_order === auditList.active_order; });                    if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].audit_id))) {                        await this.ctx.service.settleAudit.updateLastAudit(settle, auditList, shenpiInfo.audit_id);                        await this.loadRelaUser(settle);                    } else if (!shenpiInfo) {                        // 不存在终审人的状态下这里恢复为授权审批人                        this.tender.info.shenpi.settle = shenpiConst.sp_status.sqspr;                    }                }            }        }        async doSettle(transaction, settle) {            const SettleObj = require('../lib/settle');            const settleObj = new SettleObj(this.ctx);            const [settleBills, settlePos, settleSum] = await settleObj.doSettle(settle);            await transaction.delete(this.ctx.service.settleBills.tableName, { settle_id: settle.id });            if (settleBills.length > 0) await transaction.insert(this.ctx.service.settleBills.tableName, settleBills);            await transaction.delete(this.ctx.service.settlePos.tableName, { settle_id: settle.id });            if (settlePos.length > 0) await transaction.insert(this.ctx.service.settlePos.tableName, settlePos);            return settleSum;        }    }    return Settle;};
 |