| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 | 'use strict';/** * 期计量 数据模型 * * @author Mai * @date 2018/8/13 * @version */const auditConst = require('../const/audit').material;const materialConst = require('../const/material');const MaterialCalculator = require('../lib/material_calc');module.exports = app => {    class MaterialBills extends app.BaseService {        /**         * 构造函数         *         * @param {Object} ctx - egg全局变量         * @return {void}         */        constructor(ctx) {            super(ctx);            this.tableName = 'material_bills';        }        /**         * 添加工料         * @return {void}         */        async add() {            if (!this.ctx.tender || !this.ctx.material) {                throw '数据错误';            }            const order = await this._getMaxOrder(this.ctx.tender.id);            const transaction = await this.db.beginTransaction();            try {                const newBills = {                    tid: this.ctx.tender.id,                    mid: this.ctx.material.id,                    order: order + 1,                    in_time: new Date(),                };                // 新增工料                const result = await transaction.insert(this.tableName, newBills);                if (result.affectedRows !== 1) {                    throw '新增工料数据失败';                }                const insertArray = [];                const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : [];                for (const ym of material_month) {                    const one_month = {                        tid: this.ctx.tender.id,                        mid: this.ctx.material.id,                        mb_id: result.insertId,                        msg_tp: null,                        yearmonth: ym,                    };                    insertArray.push(one_month);                }                if (insertArray.length !== 0) await transaction.insert(this.ctx.service.materialMonth.tableName, insertArray);                await transaction.commit();                return await this.getDataById(result.insertId);            } catch (error) {                console.log(error);                await transaction.rollback();                throw error;            }        }        async _getMaxOrder(tenderId) {            const sql = 'SELECT Max(??) As value FROM ?? Where tid = ' + tenderId;            const sqlParam = ['order', this.tableName];            const queryResult = await this.db.queryOne(sql, sqlParam);            return queryResult.value ? queryResult.value : 0;        }        /**         * 删除工料         * @param {int} id 工料id         * @return {void}         */        async del(id) {            if (!this.ctx.tender || !this.ctx.material) {                throw '数据错误';            }            // 判断t_type是否为费用,且存在quantity,m_spread值            const transaction = await this.db.beginTransaction();            try {                const mbInfo = await this.getDataById(id);                await transaction.delete(this.tableName, { id });                let m_tp = this.ctx.material.m_tp;                if (mbInfo.t_type === materialConst.t_type[1].value && mbInfo.quantity !== null && mbInfo.m_spread !== null) {                    // 金额发生变化,则重新计算本期金额                    m_tp = await this.calcMaterialMTp(transaction);                }                const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : [];                if (material_month.length > 0) {                    await transaction.delete(this.ctx.service.materialMonth.tableName, { mb_id: id });                }                await transaction.commit();                return m_tp;            } catch (err) {                await transaction.rollback();                throw err;            }        }        /**         * 交换两个工料的顺序         * @param {Number} id1 - 工料1的id         * @param {Number} id2 - 工料2的id         * @returns {Promise<void>}         */        async changeOrder(id1, id2) {            if (!this.ctx.tender || !this.ctx.material) {                throw '数据错误';            }            const bill1 = await this.getDataByCondition({ tid: this.ctx.tender.id, id: id1 });            const bill2 = await this.getDataByCondition({ tid: this.ctx.tender.id, id: id2 });            if (!bill1 || !bill2) {                throw '数据错误';            }            const transaction = await this.db.beginTransaction();            try {                const order = bill1.order;                bill1.order = bill2.order;                bill2.order = order;                await transaction.update(this.tableName, { id: bill1.id, order: bill1.order });                await transaction.update(this.tableName, { id: bill2.id, order: bill2.order });                await transaction.commit();                return true;            } catch (err) {                await transaction.rollback();                throw err;            }        }        /**         * 修改工料信息         * @param {Object} data 工料内容         * @return {void}         */        async save(data) {            if (!this.ctx.tender || !this.ctx.material) {                throw '数据错误';            }            delete data.in_time;            // delete data.m_tp;            // 判断是否可修改            // 判断t_type是否为费用            const transaction = await this.db.beginTransaction();            try {                await transaction.update(this.tableName, data);                const m_tp = await this.calcMaterialMTp(transaction);                await transaction.commit();                return m_tp;            } catch (err) {                await transaction.rollback();                throw err;            }        }        async saveOrigin(data) {            if (!this.ctx.tender || !this.ctx.material) {                throw '数据错误';            }            return await this.db.update(this.tableName, { id: data.mb_id, origin: data.value });        }        async saveOrigins(datas) {            if (!this.ctx.tender || !this.ctx.material) {                throw '数据错误';            }            const updateData = [];            for (const data of datas) {                updateData.push({                    id: data.mb_id,                    origin: data.origin,                });            }            if (updateData.length > 0) await this.db.updateRows(this.tableName, updateData);            return true;        }        /**         * 修改工料信息         * @param {Object} data 工料内容         * @return {void}         */        async saveDatas(datas) {            if (!this.ctx.tender || !this.ctx.material) {                throw '数据错误';            }            // 判断是否可修改            // 判断t_type是否为费用            const transaction = await this.db.beginTransaction();            try {                for (const data of datas) {                    delete data.in_time;                    // delete data.m_tp;                    // console.log(data);                    await transaction.update(this.tableName, data);                }                // console.log(datas);                // await transaction.update(this.tableName, datas);                const m_tp = await this.calcMaterialMTp(transaction);                await transaction.commit();                return m_tp;            } catch (err) {                await transaction.rollback();                throw err;            }        }        /**         * 更新新一期的quantity和截止上期金额并返回本期总金额         * @param transaction         * @param tid         * @param mid         * @returns {Promise<number>}         */        async updateNewMaterial(transaction, tid, mid, ctx, stage_id, decimal) {            const materialBillsData = await this.getAllDataByCondition({ where: { tid } });            let m_tp = 0;            let m_tax_tp = 0;            const materialCalculator = new MaterialCalculator(ctx, stage_id, ctx.tender.info);            for (const mb of materialBillsData) {                const [one_tp, one_tax_tp] = await this.calcQuantityByMB(transaction, mid, mb, materialCalculator, decimal);                m_tp = this.ctx.helper.add(m_tp, one_tp);                m_tax_tp = this.ctx.helper.add(m_tax_tp, one_tax_tp);            }            return [m_tp, m_tax_tp];        }        /**         * 修改quantity,m_spread值和返回单条调差金额(新增一期)         * @param transaction         * @param mid         * @param mb         * @returns {Promise<*>}         */        async calcQuantityByMB(transaction, mid, mb, materialCalculator, decimal) {            const [newmsg_spread, newm_spread] = await this.getSpread(mb, null, decimal.up);            if (mb.t_type === materialConst.t_type[0].value) {                const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.ctx.service.materialList.tableName + ' WHERE `mid`=? AND `mb_id`=? AND `is_join`=1';                const sqlParam = [mid, mb.id];                const mb_quantity = await transaction.queryOne(sql, sqlParam);                console.log(mb_quantity);                // 取历史期记录获取截止上期调差金额,并清空本期单价和时间,来源地,重新计算价差和有效价差                const newQuantity = this.ctx.helper.round(mb_quantity.quantity, decimal.qty);                const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, newm_spread), decimal.tp);                const updateData = {                    id: mb.id,                    quantity: newQuantity,                    msg_tp: null,                    msg_times: null,                    msg_spread: newmsg_spread,                    m_spread: newm_spread,                    origin: null,                    m_tp: newTp,                    pre_tp: mb.m_tp !== null ? this.ctx.helper.add(mb.pre_tp, mb.m_tp) : mb.pre_tp,                    m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp),                    tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.add(mb.tax_pre_tp, mb.m_tax_tp) : mb.tax_pre_tp,                };                await transaction.update(this.tableName, updateData);                const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(mb_quantity.quantity, newm_spread), decimal.tp) : 0;                const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp);                return [m_tp, m_tax_tp];            } else if (mb.t_type === materialConst.t_type[1].value) {                const quantity = await materialCalculator.calculateExpr(mb.expr);                const newTp = quantity !== 0 && quantity !== null ? this.ctx.helper.round(this.ctx.helper.mul(this.ctx.helper.round(quantity, decimal.qty), newm_spread), decimal.tp) : null;                const updateData = {                    id: mb.id,                    quantity: quantity !== 0 && quantity !== null ? this.ctx.helper.round(quantity, decimal.qty) : null,                    msg_tp: null,                    msg_times: null,                    msg_spread: newmsg_spread,                    m_spread: newm_spread,                    origin: null,                    m_tp: newTp,                    pre_tp: mb.m_tp !== null ? this.ctx.helper.add(mb.pre_tp, mb.m_tp) : mb.pre_tp,                    m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp),                    tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.add(mb.tax_pre_tp, mb.m_tax_tp) : mb.tax_pre_tp,                };                await transaction.update(this.tableName, updateData);                const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(quantity, newm_spread), decimal.tp) : 0;                const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp);                return [m_tp, m_tax_tp];            }        }        /**         * 清空本期信息价后更新价差和有效价差         * @param data         * @returns {Promise<void>}         */        async getSpread(data, msg_tp, newDecimalUp = this.ctx.material.decimal.up) {            data.msg_tp = msg_tp;            const msg_spread = this.ctx.helper.round(this.ctx.helper.sub(data.msg_tp, data.basic_price), newDecimalUp);            const cor = msg_spread >= 0 ? this.ctx.helper.mul(data.basic_price, this.ctx.helper.div(data.m_up_risk, 100)) : this.ctx.helper.mul(data.basic_price, this.ctx.helper.div(data.m_down_risk, 100));            const m_spread = Math.abs(msg_spread) > Math.abs(cor) ? (msg_spread > 0 ? this.ctx.helper.round(this.ctx.helper.sub(msg_spread, cor), newDecimalUp) : this.ctx.helper.round(this.ctx.helper.add(msg_spread, cor), newDecimalUp)) : 0;            return [msg_spread, m_spread];        }        /**         * 修改 expr和quantity值,返回本期金额和单条数据         * @param data         * @returns {Promise<void>}         */        async updateFYQuantity(data) {            if (!this.ctx.tender || !this.ctx.material) {                throw '数据错误';            }            const transaction = await this.db.beginTransaction();            try {                const mbInfo = await this.getDataById(data.id);                data.m_tp = this.ctx.helper.round(this.ctx.helper.mul(data.quantity, mbInfo.m_spread), this.ctx.material.decimal.tp);                data.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(data.m_tp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp);                await transaction.update(this.tableName, data);                let m_tp = this.ctx.material.m_tp;                if (mbInfo.quantity !== data.quantity) {                    m_tp = await this.calcMaterialMTp(transaction);                }                await transaction.commit();                const returnData = {                    m_tp,                    info: await this.getDataById(data.id),                }                return returnData;            } catch (err) {                await transaction.rollback();                throw err;            }        }        // 更改计算总金额并返回值        async calcMaterialMTp(transaction) {            // 金额发生变化,则重新计算本期金额            const sql = 'SELECT SUM(`m_tp`) as total_price, SUM(IF(`m_tax_tp` is null, `m_tp`, `m_tax_tp`)) as tax_total_price FROM ' + this.tableName + ' WHERE `tid` = ? AND `is_summary` = 1';            const sqlParam = [this.ctx.tender.id];            const tp = await transaction.queryOne(sql, sqlParam);            const updateData2 = {                id: this.ctx.material.id,                m_tp: tp.total_price,                m_tax_tp: tp.tax_total_price,            };            console.log(tp);            // if (this.ctx.material.material_tax) {            //     updateData2.m_tax_tp = tp.tax_total_price;            // }            await transaction.update(this.ctx.service.material.tableName, updateData2);            return tp.total_price;        }        // 小数位变化更新单价和金额        async resetDecimal(transaction, newDecimalUp, newDecimalTp) {            const mbList = await transaction.select(this.tableName, { where: { tid: this.ctx.tender.id }, orders: [['order', 'asc']] });            const updateList = [];            const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : [];            const updateMonthList = [];            for (const mb of mbList) {                const updateData = {                    id: mb.id,                };                if (newDecimalUp !== this.ctx.material.decimal.up) {                    let newmsg_tp = this.ctx.helper.round(mb.msg_tp, newDecimalUp);                    mb.msg_tp = newmsg_tp;                    // 判断是否有月信息价,如果有则msg_tp值由月信息价的平均单价获得,并更新月信息价单价                    if (material_month.length > 0) {                        const monthList = await transaction.select(this.ctx.service.materialMonth.tableName, { where: { mb_id: mb.id, mid: this.ctx.material.id } });                        if (monthList.length !== 0) {                            for (const m of monthList) {                                // 更新月信息单价小数位                                const newMonthMsgTP = this.ctx.helper.round(m.msg_tp, newDecimalUp);                                if (m.msg_tp && newMonthMsgTP !== m.msg_tp) {                                    m.msg_tp = newMonthMsgTP;                                    updateMonthList.push({ id: m.id, msg_tp: m.msg_tp });                                }                            }                            const mb_msg_tp_sum = this._.sumBy(monthList, 'msg_tp');                            const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(monthList, 'msg_tp'), [null, '', 0]);                            newmsg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), newDecimalUp) : null;                            mb.msg_tp = newmsg_tp;                        }                    }                    const newbasic_price = this.ctx.helper.round(mb.basic_price, newDecimalUp);                    mb.basic_price = newbasic_price;                    const [newmsg_spread, newm_spread] = await this.getSpread(mb, mb.msg_tp, newDecimalUp);                    mb.m_spread = newm_spread;                    updateData.basic_price = newbasic_price;                    updateData.msg_tp = newmsg_tp;                    updateData.msg_spread = newmsg_spread;                    updateData.m_spread = newm_spread;                }                const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, mb.m_spread), newDecimalTp);                updateData.m_tp = newTp;                updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), newDecimalTp);                updateList.push(updateData);            }            if (updateMonthList.length > 0) await transaction.updateRows(this.ctx.service.materialMonth.tableName, updateMonthList);            if (updateList.length > 0) await transaction.updateRows(this.tableName, updateList);        }    }    return MaterialBills;};
 |