Explorar el Código

1. 变更令,消息埋点
2. 结算,部分代码

MaiXinRong hace 1 año
padre
commit
d06b176b73

+ 1 - 0
app/const/spec_3f.js

@@ -13,6 +13,7 @@ const pushTiming = [
     { value:'stage.checked', name: '期-审批通过' },
     { value:'stage.flow', name: '期-上报/审批' },
     { value:'revise.checked', name: '台账修订-审批通过' },
+    { value:'change.checked', name: '变更令-审批通过' },
     { value:'report.file', name: '报表-推送归档' },
 ];
 

+ 109 - 1
app/controller/settle_controller.js

@@ -9,6 +9,13 @@
  */
 
 const auditConst = require('../const/audit');
+const shenpiConst = require('../const/shenpi');
+
+const tenderConst = require('../const/tender');
+const measureType = tenderConst.measureType;
+
+const spreadConst = require('../const/spread');
+const spreadSetting = require('../lib/spread_setting');
 
 module.exports = app => {
 
@@ -41,6 +48,18 @@ module.exports = app => {
                     auditType: auditConst.auditType,
                 };
                 renderData.settles = await ctx.service.settle.getValidSettles(ctx.tender.id);
+                for (const s of renderData.settles) {
+                    if (s.status === auditConst.settle.status.uncheck) {
+                        s.curAuditors = [];
+                    } else if (s.status === auditConst.settle.status.checkNo) {
+                        s.curAuditors = await ctx.service.settleAudit.getAuditorsByStatus(sid, s.status, s.times - 1);
+                    } else {
+                        s.curAuditors = await ctx.service.settleAudit.getAuditorsByStatus(s.id, s.status, s.times);
+                    }
+                    if (s.status === auditConst.settle.status.checkNoPre) {
+                        s.curAuditorsPre = await ctx.service.stageAudit.getAuditorsByStatus(s.id, auditConst.settle.status.checking, s.times);
+                    }
+                }
                 renderData.checkedStageCount = await ctx.service.stage.count({ tid: ctx.tender.id, status: auditConst.stage.status.checked });
                 await this.layout('settle/list.ejs', renderData, 'settle/list_modal.ejs');
             } catch (err) {
@@ -128,9 +147,98 @@ module.exports = app => {
             }
         }
 
+        async _getDefaultRenderData(ctx) {
+            const data = {
+                tender: ctx.tender.data,
+                tenderMenu: JSON.parse(JSON.stringify(this.menu.settleMenu)),
+                auditConst: auditConst.settle,
+                measureType,
+                preUrl: '/tender/' + ctx.tender.id + '/settle/' + ctx.params.sorder,
+                settle: ctx.settle,
+                shenpiConst,
+                auditType: auditConst.auditType,
+            };
+            data.tenderMenu.back.children[0].url = '/tender/' + ctx.tender.id + '/measure/stage';
+            // 是否已验证手机短信
+            const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
+            data.authMobile = pa.auth_mobile;
+
+            const loadAccount = ctx.session.sessionUser.is_admin
+                ? true
+                : ctx.session.sessionUser.accountId === ctx.settle.user_id && ([auditConst.settle.status.uncheck, auditConst.settle.status.checkNo].indexOf(ctx.settle.audit_status) >= 0);
+            if (!loadAccount) return data;
+
+            // 获取所有项目参与者
+            const accountList = await ctx.service.projectAccount.getAllDataByCondition({
+                where: { project_id: ctx.session.sessionProject.id, enable: 1 },
+                columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'],
+            });
+            data.accountList = accountList;
+            const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } });
+            data.accountGroup = unitList.map(item => {
+                const groupList = accountList.filter(item1 => item1.company === item.name);
+                return { groupName: item.name, groupList };
+            });
+            return data;
+        }
+
         async index(ctx) {
-            await ctx.service.stage.loadStageAuditViewData(ctx.stage);
+            try {
+                await ctx.service.settle.loadAuditViewData(ctx.settle);
+                const renderData = await this._getDefaultRenderData(ctx);
+
+                const projectFunInfo = await this.ctx.service.project.getFunRela(ctx.session.sessionProject.id);
+                renderData.minusNoValue = projectFunInfo.minusNoValue && ctx.tender.info.fun_rela.stage_change.minusNoValue;
+                [renderData.ledgerSpread, renderData.posSpread] = await spreadSetting.getStageSpreadSetting(ctx, ctx.tender.id,
+                    this.ctx.stage.readOnly || this.ctx.stage.revising, {minusNoValue: renderData.minusNoValue});
+                renderData.whiteList = this.ctx.app.config.multipart.whitelist;
+                await this.layout('settle/index.ejs', renderData, 'settle/modal.ejs');
+            } catch(err) {
+                ctx.log(err);
+                ctx.redirect('/tender/' + ctx.tender.id + '/settle');
+            }
+        }
 
+        async _loadSettleDataByKey(ctx, key, hpack) {
+            switch (key) {
+                case 'stageBills':
+                    if (!ctx.settle.latestStage) ctx.settle.latestStage = await this.ctx.service.stage.getLastestCompleteStage(ctx.tender.id);
+                    const bills = await this._getStageBillsData(ctx);
+                    return hpack ? [this.ctx.helper.hpackArr(bills), 'stageBills'] : [bills, ''];
+                case 'stagePos':
+                    if (!ctx.settle.latestStage) ctx.settle.latestStage = await this.ctx.service.stage.getLastestCompleteStage(ctx.tender.id);
+                    const pos = await this._getStagePosData(ctx);
+                    return hpack ? [this.ctx.helper.hpackArr(pos), 'stagePos'] : [pos, ''];
+                case 'settleBills':
+                    return ctx.service.settleBills.getAllDataByCondition({ where: { settle_id: ctx.settle.id } });
+                case 'settlePos':
+                    return ctx.service.settlePos.getAllDataByCondition({ where: { settle_id: ctx.settle.id } });
+                case 'settleSelect':
+                    return ctx.service.settleSelect.getAllDataByCondition({ where: { settle_id: ctx.settle.id } });
+                    break;
+                case 'tag':
+                    return await ctx.service.ledgerTag.getDatas(ctx.tender.id, ctx.stage.id, ctx.settle.id);
+                    break;
+            }
+        }
+
+        async loadSettleData(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const filter = data.filter.split(';');
+                const responseData = { err: 0, msg: '', data: {}, hpack: [] };
+                const hpack = true;
+                for (const f of filter) {
+                    const [relaData, hpackKey] = await this._loadSettleDataByKey(f, hpack);
+                    responseData.data[f] = relaData;
+                    if (hpackKey) responseData.hpack.push(hpackKey);
+                }
+
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
         }
     }
 

+ 1 - 1
app/middleware/settle_check.js

@@ -19,7 +19,7 @@ module.exports = options => {
     return function* stageCheck(next) {
         try {
             // 读取标段数据
-            const settleOrder = parseInt(this.params.order);
+            const settleOrder = parseInt(this.params.sorder);
             if (settleOrder <= 0) throw '您访问的期不存在';
             const settle = yield this.service.settle.getDataByCondition({ tid: this.tender.id, settle_order: settleOrder });
             if (!settle) throw '您访问的期不存在';

+ 4 - 0
app/service/change.js

@@ -18,6 +18,7 @@ const SmsAliConst = require('../const/sms_alitemplate');
 const wxConst = require('../const/wechat_template');
 const pushType = require('../const/audit').pushType;
 const projectLogConst = require('../const/project_log');
+const pushOperate = require('../const/spec_3f').pushOperate;
 
 module.exports = app => {
     class Change extends app.BaseService {
@@ -906,6 +907,9 @@ module.exports = app => {
 
                     await this.ctx.service.changeAuditList.updateToLedger(this.transaction, changeData.tid, changeData.cid);
 
+                    // 审批通过 - 检查三方特殊推送
+                    await this.ctx.service.specMsg.addChangeMsg(transaction, this.ctx.session.sessionProject.id, changeData, pushOperate.change.checked);
+
                     // 添加短信通知-审批通过提醒功能
                     // const mobile_array = [];
                     const auditList = await this.ctx.service.changeAudit.getListGroupByTimes(changeData.cid, changeData.times);

+ 9 - 1
app/service/ledger_tag.js

@@ -30,11 +30,15 @@ module.exports = app => {
          * @param {Number} sid - 期id(-1时查询台账分解全部标签)
          * @returns {Promise<void>}
          */
-        async getDatas(tid, sid = -1) {
+        async getDatas(tid, sid = -1, settleId = -1) {
             const sql = 'SELECT la.id, la.uid, la.lid, la.share, la.color, la.comment, pa.name as u_name FROM ' + this.tableName + ' la ' +
                 '  LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' pa ON la.uid = pa.id' +
                 '  WHERE la.tid = ? and la.sid = ? and (la.uid = ? or la.share) ORDER BY la.create_time DESC';
             return await this.db.query(sql, [tid, sid, this.ctx.session.sessionUser.accountId]);
+            // const sql = 'SELECT la.id, la.uid, la.lid, la.share, la.color, la.comment, pa.name as u_name FROM ' + this.tableName + ' la ' +
+            //     '  LEFT JOIN ' + this.ctx.service.projectAccount.tableName + ' pa ON la.uid = pa.id' +
+            //     '  WHERE la.tid = ? and la.sid = ? and la.settle_id = ? and (la.uid = ? or la.share) ORDER BY la.create_time DESC';
+            // return await this.db.query(sql, [tid, sid, settleId, this.ctx.session.sessionUser.accountId]);
         }
 
         /**
@@ -61,6 +65,10 @@ module.exports = app => {
                 data.sid = this.ctx.stage.id;
                 data.sorder = this.ctx.stage.order;
             }
+            if (this.ctx.settle) {
+                data.settle_id = this.ctx.settle.id;
+                data.settle_order = this.ctx.settle.settle_order;
+            }
             const result = await this.db.insert(this.tableName, data);
             data.id = result.insertId;
             data.u_name = this.ctx.session.sessionUser.name;

+ 7 - 10
app/service/settle.js

@@ -155,7 +155,7 @@ module.exports = app => {
             settle.finalAuditorIds = settle.userGroups[settle.userGroups.length - 1].map(x => { return x.aid; });
 
             // 协作相关
-            settle.assists = await this.service.settleAuditAss.getData(settle); // 全部协同人
+            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;
             }); // 过滤无效协同人
@@ -216,7 +216,7 @@ module.exports = app => {
                     return;
                 }
 
-                const preAuditors = settle.curAuditors[0].order !== 1 ? settle.auditors.filter(x => { return x.order === settle.curAuditors[0].order - 1; }) : [];
+                const preAuditors = settle.curAuditors[0] && settle.curAuditors[0].order !== 1 ? settle.auditors.filter(x => { return x.order === settle.curAuditors[0].order - 1; }) : [];
                 const preAuditorCheckAgain = preAuditors.find(pa => { return pa.status === status.checkAgain; });
                 const preAuditorCheckCancel = preAuditors.find(pa => { return pa.status === status.checkCancel; });
                 const preAuditorHasOld = preAuditors.find(pa => { return pa.is_old === 1; });
@@ -249,7 +249,7 @@ module.exports = app => {
         async _doCheckSettleReadOnly(settle) {
             const status = auditConst.settle.status;
             // 校验权限(参与人、分享、游客)
-            const accountId = this.session.sessionUser.accountId;
+            const accountId = this.ctx.session.sessionUser.accountId;
             const shareIds = [];
             // 是否只读
             if (settle.status === status.uncheck || settle.status === status.checkNo) {
@@ -286,15 +286,15 @@ module.exports = app => {
             }
 
             // 上传文件权限
-            const permission = this.session.sessionUser.permission;
-            if (settle.userIds.indexOf(accountId) >= 0 || this.session.sessionUser.is_admin) {
+            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.status === status.uncheck) throw '您无权查看该数据';
                     settle.filePermission = false;
-                } else if (this.tender.isTourist || this.session.sessionUser.is_admin) {
-                    settle.filePermission = this.tender.touristPermission.file || settle.auditorIds.indexOf(accountId) !== -1;
+                } 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 '您无权查看该数据';
                 }
@@ -303,9 +303,6 @@ module.exports = app => {
         async doCheckSettle(settle) {
             // 读取原报、审核人等参与人数据
             await this.loadRelaUser(settle);
-            // 是否台账修订中
-            const lastRevise = await this.service.ledgerRevise.getLastestRevise(this.tender.id);
-            settle.revising = (lastRevise && lastRevise.status !== auditConst.revise.status.checked) || false;
             // 是否只读等权限
             await this._doCheckSettleReadOnly(settle);
             // 可否撤回,是哪一种撤回

+ 9 - 0
app/service/settle_audit.js

@@ -9,6 +9,7 @@
  */
 
 const auditConst = require('../const/audit');
+const auditType = auditConst.auditType;
 
 module.exports = app => {
     class SettleAudit extends app.BaseService {
@@ -43,11 +44,19 @@ module.exports = app => {
             return result;
         }
 
+        // 去重
         async getUniqAuditorsGroup(settleId, times) {
             const group = await this.getAuditorGroup(settleId, times);
             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]);
+            if (!cur) return [];
+
+            return await this.getAllDataByCondition({ where: { settle_id: settleId, audit_times: times, audit_order: cur.audit_order}});
+        }
+
         async getAuditorHistory(settleId, times, reverse = false) {
             const history = [];
             if (times >= 1) {

+ 6 - 0
app/service/spec_msg.js

@@ -59,6 +59,12 @@ module.exports = app => {
             await transaction.insert(this.tableName, { pid, tid: stage.tid, sid: stage.id, timing });
         }
 
+        async addChangeMsg(transaction, pid, change, timing) {
+            const needMsg = await this.tenderNeedMsg(pid, change.tid, timing);
+            if (!needMsg) return;
+            await transaction.insert(this.tableName, { pid, tid: change.tid, cid: change.cid, timing });
+        }
+
         async addReportMsg(transaction, pid, tender, stage, timing) {
             const needMsg = await this.tenderNeedMsg(pid, stage.tid, timing);
             if (!needMsg) return;

+ 0 - 0
app/view/settle/index.ejs


+ 12 - 12
app/view/settle/list.ejs

@@ -35,15 +35,15 @@
                     <% for (const [i,s] of settles.entries()) { %>
                     <tr>
                         <td>
-                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.order %>" target="_blank">第 <%- s.order %> 期</a>
+                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.settle_order %>" target="_blank">第 <%- s.settle_order %> 期</a>
                             <% if ((i === 0 || (settles[i-1] && settles[i-1].status !== auditConst.status.checked)) && s.user_id === ctx.session.sessionUser.accountId) { %>
                             <a href="#edit" class="edit-stage" data-index="<%- i %>" data-toggle="modal" data-target="#edit"><i class="fa fa-pencil-square-o "></i></a>
                             <% } %>
                         </td>
-                        <td class="text-center"><%- s.s_time %></td>
+                        <td class="text-center"><%- s.settle_time %></td>
                         <td class="text-center">
-                            <span data-toggle="tooltip" data-placement="bottom" data-original-title="<%- (s.period ? s.period : '') %>">
-                                <%- (s.period ? (s.period.split('~')[1] ? s.period.split('~')[1] : s.period)  : '') %>
+                            <span data-toggle="tooltip" data-placement="bottom" data-original-title="<%- (s.settle_period ? s.settle_period : '') %>">
+                                <%- (s.settle_period ? (s.settle_period.split('~')[1] ? s.settle_period.split('~')[1] : s.settle_period)  : '') %>
                             </span>
                         </td>
                         <% if (ctx.tender.info.display.thousandth) { %>
@@ -60,24 +60,24 @@
                         <td class="text-right"><%- (s.end_tp ? s.end_tp : '')%></td>
                         <% } %>
                         <td class="<%- auditConst.auditProgressClass[s.status] %>">
-                            <% if (s.curAuditors.length > 0) { %>
+                            <% if (s.curAuditors && s.curAuditors.length > 0) { %>
                             <% if (s.curAuditors[0].audit_type === auditType.key.common) { %>
-                            <a href="#sp-list" data-toggle="modal" data-target="#sp-list" s-order="<%- s.order %>"><%- s.curAuditors[0].name %><%if (s.curAuditors[0].role !== '' && s.curAuditors[0].role !== null) { %>-<%- s.curAuditors[0].role %><% } %></a>
+                            <a href="#sp-list" data-toggle="modal" data-target="#sp-list" s-order="<%- s.settle_order %>"><%- s.curAuditors[0].name %><%if (s.curAuditors[0].role !== '' && s.curAuditors[0].role !== null) { %>-<%- s.curAuditors[0].role %><% } %></a>
                             <% } else { %>
-                            <a href="#sp-list" data-toggle="modal" data-target="#sp-list" s-order="<%- s.order %>"><%- ctx.helper.transFormToChinese(s.curAuditors[0].audit_order) + '审' %></a>
+                            <a href="#sp-list" data-toggle="modal" data-target="#sp-list" s-order="<%- s.settle_order %>"><%- ctx.helper.transFormToChinese(s.curAuditors[0].audit_order) + '审' %></a>
                             <% } %>
                             <% } %>
                             <%- auditConst.auditProgress[s.status] %>
                         </td>
                         <td class="text-center">
                             <% if (s.status === auditConst.status.uncheck && s.user_id === ctx.session.sessionUser.accountId) { %>
-                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
+                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.settle_order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
                             <% } else if (s.status === auditConst.status.checkNo && s.curAuditors && s.user_id === ctx.session.sessionUser.accountId) { %>
-                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
+                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.settle_order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
                             <% } else if (s.status === auditConst.status.checking && s.curAuditors && s.curAuditors.findIndex(x => { return x.aid === ctx.session.sessionUser.accountId; }) >= 0) { %>
-                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
-                            <% } else if (s.status === auditConst.status.checkNoPre && s.curAuditors && s.curAuditor2.findIndex(x => { return x.aid === ctx.session.sessionUser.accountId; }) >= 0) { %>
-                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
+                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.settle_order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
+                            <% } else if (s.status === auditConst.status.checkNoPre && s.curAuditorsPre && s.curAuditorsPre.findIndex(x => { return x.aid === ctx.session.sessionUser.accountId; }) >= 0) { %>
+                            <a href="<%- '/tender/' + ctx.tender.id + '/settle/' + s.settle_order %>" target="_blank" class="btn <%- auditConst.statusButtonClass[s.status] %> btn-sm"><%- auditConst.statusButton[s.status] %></a>
                             <% } else { %>
                             <span class="<%- auditConst.auditStringClass[s.status] %>"><%- auditConst.auditString[s.status] %></span>
                             <% } %>

+ 7 - 7
app/view/settle/list_modal.ejs

@@ -66,7 +66,7 @@
             <div class="modal-body">
                 <div class="form-group">
                     <label>期</label>
-                    <input class="form-control form-control-sm" id="edit-name" value="第 <%- stages[0].order %> 期" type="text" readonly="" name="name">
+                    <input class="form-control form-control-sm" id="edit-name" value="第 <%- settles[0].order %> 期" type="text" readonly="" name="name">
                 </div>
                 <div class="form-group">
                     <label>结算年月<b class="text-danger">*</b></label>
@@ -79,7 +79,7 @@
             </div>
             <div class="modal-footer">
                 <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
-                <input type="hidden" name="order" id="edit-order" value="<%- stages[0].order %>">
+                <input type="hidden" name="order" id="edit-order" value="<%- settles[0].order %>">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <button type="submit" class="btn btn-primary btn-sm" id="edit-ok" >确定修改</button>
             </div>
@@ -101,13 +101,13 @@
     $('.edit-stage').on('click', function () {
         const index = parseInt($(this).data('index'));
         const editDate = $('#edit-date').datepicker().data('datepicker');
-        $('#edit-name').val('第 ' + stages[index].order + ' 期');
-        $('#edit-order').val(stages[index].order);
-        if (stages[index].s_time && stages[index].s_time !== '') {
-            editDate.selectDate(new Date(stages[index].s_time));
+        $('#edit-name').val('第 ' + settles[index].order + ' 期');
+        $('#edit-order').val(settles[index].order);
+        if (settles[index].s_time && settles[index].s_time !== '') {
+            editDate.selectDate(new Date(settles[index].s_time));
         }
         const period = [];
-        for (const p of stages[index].period.split('~')) {
+        for (const p of settles[index].period.split('~')) {
             if (p && p !== '') {
                 period.push(new Date(p));
             }

+ 0 - 0
app/view/settle/modal.ejs


+ 24 - 0
db_script/baseUtils.js

@@ -153,6 +153,26 @@ const ZhCalc = {
     },
 };
 
+const recursiveMkdirSync = async function(pathName) {
+    if (!fs.existsSync(pathName)) {
+        const upperPath = path.dirname(pathName);
+        if (!fs.existsSync(upperPath)) {
+            await recursiveMkdirSync(upperPath);
+        }
+        await fs.mkdirSync(pathName);
+    }
+};
+const saveBufferFile = async function(buffer, fileName) {
+    // 检查文件夹是否存在,不存在则直接创建文件夹
+    const pathName = path.dirname(fileName);
+    if (!fs.existsSync(pathName)) {
+        await recursiveMkdirSync(pathName);
+    }
+    await fs.writeFileSync(fileName, buffer);
+};
+
+
+
 module.exports = {
     querySql,
     filterLastestData,
@@ -160,4 +180,8 @@ module.exports = {
         pool.end();
     },
     ZhCalc,
+    saveBufferFile,
+    getFileName: function(fileName) {
+        return path.join(__dirname, fileName);
+    },
 };