/** * Created by chen on 2017/6/29. */ let mongoose = require('mongoose'); const uuidV1 = require('uuid/v1'); let consts = require('../../main/models/project_consts') let commonConsts = consts.commonConst; let _ = require("lodash"); let ration_glj = mongoose.model('ration_glj'); import GLJListModel from '../../glj/models/glj_list_model'; let std_glj_lib_gljList_model = mongoose.model('std_glj_lib_gljList'); let async_n = require("async"); let ration = mongoose.model('ration'); let ration_coe_facade = require('./ration_coe_facade'); let ration_coe = mongoose.model('ration_coe'); let std_ration_lib_ration_items = mongoose.model('std_ration_lib_ration_items'); let glj_calculate_facade = require('./glj_calculate_facade'); let glj_type_util = require('../../../public/cache/std_glj_type_util'); let quantity_detail_facade = require('../../main/facade/quantity_detail_facade'); let ration_installation_facade = require('../../main/facade/ration_installation_facade'); let logger = require("../../../logs/log_helper").logger; import stdgljutil from "../../../public/cache/std_glj_type_util"; import EngineeringLibModel from "../../users/models/engineering_lib_model"; import GljDao from "../../complementary_glj_lib/models/gljModel"; const complementaryGljModel = mongoose.model('complementary_glj_lib'); const stdGljModel = mongoose.model('std_glj_lib_gljList'); const gljClassModel = mongoose.model('std_glj_lib_gljClass'); const projectDao = require('../../pm/models/project_model').project; module.exports = { save: save, getData: getData, deleteByRation: deleteByRation, getQuantityByProjectGLJ: getQuantityByProjectGLJ, getLibInfo: getLibInfo, getGLJData: getGLJData, addGLJ: addGLJ, replaceGLJ: replaceGLJ, mReplaceGLJ: mReplaceGLJ, updateRationGLJByEdit: updateRationGLJByEdit, getGLJClass: getGLJClass, insertGLJAsRation: insertGLJAsRation, getRationTypeGLJQuantity:getRationTypeGLJQuantity, getInfoFromProjectGLJ:getInfoFromProjectGLJ, createNewRecord:createNewRecord, getGLJSearchInfo:getGLJSearchInfo, updateRationGLJFromDoc:updateRationGLJFromDoc } let operationMap = { 'ut_create': create_ration_glj, 'ut_update': update_ration_glj, 'ut_delete': delete_ration_glj }; let updateFunctionMap = { 'normalUpdate': normalUpdate }; /** * 根据项目工料机ID和项目ID取消耗量 * * @param {object} condition * @return Array */ async function getQuantityByProjectGLJ(condition) { let query = { 'projectID': condition.projectID, }; if(condition.projectGLJIDList){ query['projectGLJID'] = {$in: condition.projectGLJIDList}; } let startTime = +new Date(); let results = await ration_glj.find(query, ['projectGLJID', 'quantity', 'rationID'], {sort: {projectGLJID: 1}}); let rationList = _.uniq(_.map(results, 'rationID')); let getQuantity = +new Date(); console.log("取工料机消耗量时间-----"+(getQuantity - startTime)); let rationQuery = { 'projectID': condition.projectID, 'ID': {$in: rationList}, 'deleteInfo': null }; /* $and: [ {'projectID': condition.projectID}, {'ID': {$in: rationList}}, {'deleteInfo': null} ]*/ let rations = await ration.find(rationQuery, ['ID', 'quantity']); let rationsTime = +new Date(); console.log("取定额消耗量时间-----"+(rationsTime - getQuantity)); return combineQuantity(results, rations); } function combineQuantity(results, rations) { let resultList = []; let rationMap = _.indexBy(rations,'ID'); for(let r of results){ let tmp = { projectGLJID: r.projectGLJID, quantity: Number(r.quantity) } let ration = rationMap[r.rationID];//_.find(rations, {ID: r.rationID}) if (ration) { tmp.rationID = ration.ID; tmp.rationQuantity = ration.quantity ? Number(ration.quantity) : undefined; } resultList.push(tmp); } return resultList; return resultList; } function get_lib_glj_info(ration_glj) { return function (result, cb) { std_glj_lib_gljList_model.findOne({'ID': ration_glj.GLJID}, (err, glj) => { if (err) { cb(err, '') } else if (glj) { ration_glj.name = glj.name; ration_glj.code = glj.code; ration_glj.original_code = glj.code; ration_glj.unit = glj.unit; ration_glj.specs = glj.specs; ration_glj.basePrice = glj.basePrice; ration_glj.marketPrice = glj.basePrice; ration_glj.shortName = glj.shortName; ration_glj.type = glj.gljType; ration_glj.repositoryId = glj.repositoryId; ration_glj.adjCoe = glj.adjCoe; getInfoFromProjectGLJ(ration_glj).then(function (info) { if (info) { let tem = {}; tem.newRecode = createNewRecord(info); tem.showData = info; result.datas.push(tem); cb(null, result); } else { cb(new Error('get project glj error'), null); } }); } else { cb(null, result); } }) } } function createNewRecord(ration_glj) { let newRecoed = {}; newRecoed.ID = ration_glj.ID; newRecoed.projectID = ration_glj.projectID; newRecoed.GLJID = ration_glj.GLJID; newRecoed.rationID = ration_glj.rationID; newRecoed.rationItemQuantity = ration_glj.rationItemQuantity; newRecoed.quantity = ration_glj.quantity; newRecoed.name = ration_glj.name; newRecoed.code = ration_glj.code; newRecoed.original_code = ration_glj.original_code; newRecoed.unit = ration_glj.unit; newRecoed.specs = ration_glj.specs; newRecoed.from = ration_glj.from ? ration_glj.from : 'std'; newRecoed.createType = ration_glj.createType ? ration_glj.createType : 'normal'; newRecoed.shortName = ration_glj.shortName; newRecoed.billsItemID = ration_glj.billsItemID; newRecoed.type = ration_glj.type; newRecoed.model = ration_glj.model; newRecoed.repositoryId = ration_glj.repositoryId; newRecoed.projectGLJID = ration_glj.projectGLJID; newRecoed.adjCoe = ration_glj.adjCoe; return newRecoed } async function getInfoFromProjectGLJ(ration_glj,unitPriceFileId,ext) { let data = getGLJSearchInfo(ration_glj); try { let projectGljModel = new GLJListModel(); let result = await projectGljModel.addList(data,unitPriceFileId,ext); let typeString = result.type+""; ration_glj.marketPrice = result.unit_price.market_price; ration_glj.adjustPrice = result.unit_price.base_price; ration_glj.basePrice = result.unit_price.base_price; ration_glj.projectGLJID = result.id; if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估 ration_glj.isEstimate = result.is_evaluate; } if (result.hasOwnProperty('subList') && result.subList.length > 0) { ration_glj.subList = getMixRatioShowDatas(result.subList); } return ration_glj; } catch (err) { logger.err(err); return null; } } function getMixRatioShowDatas(subList) { var temRationGLJs = []; for (let pg of subList) { var tem = { projectGLJID: pg.id, code: pg.code, name: pg.name, specs: pg.specs, unit: pg.unit, shortName: pg.unit_price.short_name, rationItemQuantity: pg.ratio_data.consumption, basePrice: pg.unit_price.base_price, marketPrice: pg.unit_price.market_price, adjustPrice: pg.adjust_price, isEstimate: pg.is_evaluate, isMixRatio: true, isAdd: pg.unit_price.is_add, GLJID: pg.glj_id } temRationGLJs.push(tem); } temRationGLJs = _.sortBy(temRationGLJs, 'code'); return temRationGLJs; } function create_ration_glj(user_id, datas) { return function (callback) { let ration_glj_list = datas.ration_glj_list; var tasks = []; tasks.push(startingTask("get glj info")) for (let i = 0; i < ration_glj_list.length; i++) { ration_glj_list[i].ID = uuidV1(); tasks.push(get_lib_glj_info(ration_glj_list[i])) } async_n.waterfall(tasks, (err, results) => { if (err) { callback(err, results) } else { let newRecords = []; let showDatas = []; for (let r of results.datas) { if (r) { newRecords.push(r.newRecode); showDatas.push(r.showData); } } if (newRecords.length > 0) { ration_glj.insertMany(newRecords, (err, doc) => { if (err) { callback(err, null); } else { let returndata = { updateTpye: commonConsts.UT_CREATE, moduleName: 'ration_glj', data: { newRecords: newRecords, showDatas: showDatas } } callback(null, returndata) } }); } else { logger.info("can't find gljs") callback(null, null) } } }) } } function update_ration_glj(user_id, datas) { if (datas.updateFunction) { return updateFunctionMap[datas.updateFunction](user_id, datas); } else { return normalUpdate(user_id, datas); } } function normalUpdate(user_id, datas) { return function (callback) { ration_glj.update(datas.query, datas.doc, (err, result) => { if (err) { callback(err, ''); } else { let returndata = { moduleName: 'ration_glj', data: { updateTpye: commonConsts.UT_UPDATE, query: datas.query, doc: datas.doc } } callback(null, returndata) } }) } } async function doCustomQuantityUpdate(datas) { let result = await ration_glj.findOneAndUpdate(datas.query, datas.doc); let cal_result = await glj_calculate_facade.calculateQuantity({ projectID: datas.query.projectID, rationID: datas.query.rationID }); cal_result.glj_result.forEach(function (item) { if (!item.doc.hasOwnProperty('customQuantity')) { item.doc.customQuantity = null; } }); return cal_result; } function delete_ration_glj(user_id, datas) { return function (callback) { deleteByID(datas, callback); //callback(new Error("删除子数据失败!"),null) //这个方法已经不用,先注释,稳定后再删除 /* if (datas.deleteType == "RATION") { deleteByRation(datas, callback); } else if (datas.deleteType == "BILL") { deleteByBill(user_id, datas, callback); } else { deleteByID(datas, callback); }*/ } } function deleteByRation(datas, callback) { let data = datas.updateData; let tasks = []; tasks.push(deleteGLJList(data)); tasks.push(ration_coe_facade.delete_ration_coe(data)); tasks.push(quantity_detail_facade.deleteByRation(data)); tasks.push(ration_installation_facade.deleteByRation(data)); async_n.parallel(tasks, function (err, result) { commonCallback(callback, result, err) }) } function deleteGLJList(data) { return function (callback) { ration_glj.deleteMany({projectID: data.projectID, rationID: data.ID}, (err, result) => { commonCallback(callback, result, err) }); } } function deleteByBill(user_id, datas, callback) { let tasks = []; tasks.push(startingTask("deleteByBill")); tasks.push(getRationsByBill(datas)); tasks.push(deleteRationsbyBill(user_id, datas)); tasks.push(deleteByMultiRations(datas)); async_n.waterfall(tasks, function (err, results) { if (err) { callback(err, ''); } else { callback(null, results); } }) } function deleteByID(datas, callback) { deleteAndUpdateState(datas).then(function (result) { if (result.err) { callback(result.err, ''); } else { let returndata = { moduleName: 'ration_glj', data: { updateTpye: commonConsts.UT_DELETE, query: datas.query, adjustState: result.adjustState } } callback(null, returndata) } }) } async function deleteAndUpdateState(datas) { let result = { err: null } try { await ration_glj.deleteOne(datas.query); let stateResult = await glj_calculate_facade.calculateQuantity({ projectID: datas.query.projectID, rationID: datas.doc.rationID }); result.adjustState = stateResult.adjustState; } catch (err) { result.err = err; } return result; } function startingTask(processName) { return function (asyncCallBack) { var result = { processName: processName, datas: [] }; asyncCallBack(null, result); }; } function getRationsByBill(datas) { return function (results, callback) { ration.find({ projectID: datas.updateData.projectID, billsItemID: datas.updateData.ID }, function (err, rations) { if (err) { callback(err, '') } else { results.rations = rations; callback(null, results) } }) } } function deleteRationsbyBill(user_id, datas) { return function (results, callback) { let deleteInfo = { deleteInfo: {deleted: true, deleteDateTime: new Date(), deleteBy: user_id} }; ration.update({ projectID: datas.updateData.projectID, billsItemID: datas.updateData.ID }, deleteInfo, {multi: true}, (err, deleteresults) => { if (err) { callback(err, ''); } else { callback(null, results); } }); } } function deleteByMultiRations(datas) { return function (results, deleteCallBack) { var delete_tasks = []; var deleteOne = function (ration) { return function (callback) { ration_glj.deleteMany({projectID: ration.projectID, rationID: ration.ID}, function (err, result) { commonCallback(callback, result, err) }); } } let rations = results.rations; for (let i = 0; i < rations.length; i++) { delete_tasks.push(deleteOne(rations[i]._doc)); delete_tasks.push(ration_coe_facade.delete_ration_coe(rations[i]._doc)); delete_tasks.push(quantity_detail_facade.deleteByRation(rations[i]._doc)); delete_tasks.push(ration_installation_facade.deleteByRation(rations[i]._doc)); } delete_tasks.push(quantity_detail_facade.deleteByBill(datas.updateData)); async_n.parallel(delete_tasks, (err, results) => { if (err) { deleteCallBack(err, '') } else { deleteCallBack(null, results) } }) } } /* function deleteByRation(doc) { return function (callback){ ration_glj.deleteMany({projectID: doc.updateData.projectID, rationID: doc.updateData.ID},callback); } } */ function save(user_id, datas, callback) { let operations = []; if (_.isArray(datas)) { for (let i = 0; i < datas.length; i++) { operations.push(operationMap[datas[i].updateType](user_id, datas[i])); } } else { operations.push(operationMap[datas.updateType](user_id, datas)); } async_n.parallel(operations, function (err, results) { if (err) { callback(err, ''); } else { if (results.length == 1) { callback(null, results[0]) } else { callback(null, results) } } }) } async function getLibInfo(req) { let gljLibId = null, engineerID, sessionCompilation = req.session.sessionCompilation, engineeringLibModel = new EngineeringLibModel() ; engineerID = req.params.engineerID; if(engineerID){ let engineeringInfo = await engineeringLibModel.findDataByCondition({'_id': engineerID}); gljLibId = engineeringInfo.glj_lib.length > 0 && typeof engineeringInfo.glj_lib !== 'undefined' ? engineeringInfo.glj_lib[0].id : null; }else { throw new Error("工程专业ID为空!"); } let data = { userID: req.session.sessionUser.id, gljLibId: gljLibId, compilationId: sessionCompilation._id }; return data; } function getGLJData(info, callback) { let gljDao = new GljDao(); let datas = {}; let gljDistTypeCache = stdgljutil.getStdGljTypeCacheObj().toArray(); datas.distTypeTree = gljDistTypeCache; async_n.parallel([ function (cb) { gljDao.getGljTypes(info.gljLibId, function (err, data) { if (err) { cb(err); } else { datas.treeData = data; cb(null); } }) }, function (cb) { gljDao.getGljItems(info.gljLibId, info.userID, info.compilationId, function (err, data) { if (err) { cb(err); } else { datas.stdGLJ = data.stdGljs; datas.complementaryGLJs = data.complementaryGljs; cb(null); } }); } ], function (err) { if (err) { callback(true, null); } else { callback(false, datas); } }) } function getGLJSearchInfo(ration_glj) { let data = { glj_id: ration_glj.GLJID, project_id: ration_glj.projectID, code: ration_glj.code, original_code: ration_glj.original_code, name: ration_glj.name, //shortName: ration_glj.shortName, specs: ration_glj.specs, unit: ration_glj.unit, type: ration_glj.subType ? ration_glj.subType : ration_glj.type,//如果有subType,则是通过插入定额级的工料机进来的 model: ration_glj.model, type_of_work: ration_glj.subType ? ration_glj.subType : ration_glj.type, base_price: ration_glj.basePrice, market_price: ration_glj.marketPrice, repositoryId: ration_glj.repositoryId, adjCoe: ration_glj.adjCoe, materialType:ration_glj.materialType, materialCoe:ration_glj.materialCoe, from: ration_glj.from ? ration_glj.from : 'std'//std:标准工料机库, cpt:补充工料机库 }; let glj_type_object = glj_type_util.getStdGljTypeCacheObj(); let type = glj_type_object.getItemById(data.type); data.shortName = type.shortName; if (data.from == 'cpt') {//从补充工料机来的数据即为新增数据 data.is_add = 1; } return data; } async function prepareExtData(projectID,compilation) { let ext , unitFileId ; let property = await projectDao.getProjectProperty(projectID); ext = projectDao.getExtendData(property,compilation); unitFileId = property.unitPriceFile !== undefined ? property.unitPriceFile.id : 0; return [unitFileId,ext]; } async function addGLJ(rgList,compilation) { let newRecodes = []; if (rgList.length <= 0) return {}; let [unitFileId,ext] = await prepareExtData(rgList[0].projectID,compilation); for (let g of rgList) { let projectGljModel = new GLJListModel(); let result = await projectGljModel.addList(getGLJSearchInfo(g),unitFileId,ext); let typeString = result.type+''; g.marketPrice = result.unit_price.market_price; g.adjustPrice = result.unit_price.base_price; g.basePrice = result.unit_price.base_price; g.isAdd = result.unit_price.is_add; g.projectGLJID = result.id; if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估 g.isEstimate = result.is_evaluate; } g.ID = uuidV1(); if (result.hasOwnProperty('subList') && result.subList.length > 0) { g.subList = getMixRatioShowDatas(result.subList); } newRecodes.push(createNewRecord(g)); } await ration_glj.insertMany(newRecodes); let stateResult = await glj_calculate_facade.calculateQuantity({ projectID: rgList[0].projectID, rationID: rgList[0].rationID }); let result = { newRecodes: newRecodes, showData: rgList, adjustState: stateResult.adjustState } return result; } async function replaceGLJ(data,compilation) { let rdata = {}; let projectGljModel = new GLJListModel(); let [unitFileId,ext] = await prepareExtData(data.projectID,compilation); let result = await projectGljModel.addList(getGLJSearchInfo(data),unitFileId,ext); let typeString = result.type+''; data.projectGLJID = result.id; let updateResult = await ration_glj.findOneAndUpdate({ID: data.ID, projectID: data.projectID}, data);//更新定额工料机 //组装回传数据 data.marketPrice = result.unit_price.market_price; data.adjustPrice = result.unit_price.base_price; data.basePrice = result.unit_price.base_price; data.isAdd = result.unit_price.is_add; if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估 data.isEstimate = result.is_evaluate; } if (result.hasOwnProperty('subList') && result.subList.length > 0) { data.subList = getMixRatioShowDatas(result.subList); } let stateResult = await glj_calculate_facade.calculateQuantity({ projectID: data.projectID, rationID: data.rationID }, true,true); rdata.data = data; rdata.adjustState = stateResult.adjustState; rdata.name = stateResult.rationName; return rdata; } async function mReplaceGLJ(data,compilation) { let mresult = {}; let projectGljModel = new GLJListModel(); let [unitFileId,ext] = await prepareExtData(data.doc.projectID,compilation); // let result = await projectGljModel.addList(getGLJSearchInfo(data.doc),unitFileId,ext); let typeString = result.type+''; let newDoc = {}; newDoc.projectGLJID = result.id; let rationList = await ration_glj.distinct('rationID', data.query); for(let t of data.tasks){ t.updateOne.update.projectGLJID = result.id;//更新项目工料机ID } await ration_glj.bulkWrite(data.tasks); //let updateResult = await ration_glj.update(data.query, data.doc, {multi: true}); newDoc.marketPrice = result.unit_price.market_price; newDoc.adjustPrice = result.unit_price.base_price; newDoc.basePrice = result.unit_price.base_price; newDoc.isAdd = result.unit_price.is_add; if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估 newDoc.isEstimate = result.is_evaluate; } if (result.hasOwnProperty('subList') && result.subList.length > 0) { newDoc.subList = getMixRatioShowDatas(result.subList); } let stateList = await changAdjustState(data, rationList); data.doc = newDoc; mresult.data = data; mresult.stateList = stateList; return mresult } async function updateRationGLJByEdit(data) { var doc = data.doc; var result; if (doc.hasOwnProperty('customQuantity')) { result = await doCustomQuantityUpdate(data) } else { result = await doRationGLJUpdate(data); } return result; } async function updateRationGLJFromDoc(rg,doc,priceInfo) { let gljListModel = new GLJListModel(); let projectGLJ = getGLJSearchInfo(rg); for (let key in doc) { projectGLJ[key] = doc[key] } projectGLJ.base_price = priceInfo.base_price; projectGLJ.market_price = priceInfo.market_price; let projcetGLJ_n = await gljListModel.modifyGLJ(projectGLJ, rg); doc.code = projcetGLJ_n.code; doc.projectGLJID = projcetGLJ_n.id; if (projcetGLJ_n.unit_price.is_add == 1) { doc.createType = 'replace'; doc.rcode = projcetGLJ_n.original_code; } else { doc.createType = 'normal'; doc.rcode = ''; } await ration_glj.findOneAndUpdate({ID:rg.ID}, doc); return [projcetGLJ_n,doc] } async function doRationGLJUpdate(data) { let resutl = {}; let priceInfo = data.priceInfo; let rg = await ration_glj.findOne(data.query); let [projcetGLJ_n,doc] = await updateRationGLJFromDoc(rg,data.doc,priceInfo); //取价格 let gljListModel = new GLJListModel(); gljListModel.getGLJPrice(projcetGLJ_n); doc.basePrice = projcetGLJ_n.unit_price.base_price; doc.marketPrice = projcetGLJ_n.unit_price.market_price; doc.adjustPrice = projcetGLJ_n.adjust_price; doc.isAdd = projcetGLJ_n.unit_price.is_add; resutl.doc = doc; let stateResult = await glj_calculate_facade.calculateQuantity({ projectID: data.query.projectID, rationID: data.query.rationID },null,true); resutl.adjustState = stateResult.adjustState; resutl.name = stateResult.rationName; return resutl; } async function getGLJClass(info, data) { let result = { exist: false } //检查补充工料机中是否已经存在一样的记录了 let condition = { userId: info.userID, compilationId: info.compilationId, code: data.code, name: data.name, unit: data.unit, gljType: data.type, basePrice: data.basePrice } if (data.specs != null && data.specs != undefined && data.specs != '') { condition['specs'] = data.specs; } let glj = await complementaryGljModel.find(condition); if (glj.length > 0) { //如果已存在就直接返回,不用再新增了 result.exist = true; return result } //查找工料机类型树 let items = await gljClassModel.find({ "repositoryId": info.gljLibId, "$or": [{"isDeleted": null}, {"isDeleted": false}] }); result.items = items; return result; } async function insertGLJAsRation(data,compilation) { let gljList = data.gljList; if (data.hasOwnProperty("selectedSerialNo")) { //如果需要,更新序列号。 let query = { projectID: data.projectID, billsItemID: data.billsItemID, serialNo: {$gt: data.selectedSerialNo} } await ration.update(query, {$inc: {serialNo: gljList.length}}, {multi: true}); } let [unitFileId,ext] = await prepareExtData(data.doc.projectID,compilation); for (let glj of gljList) { let p_glj = getGLJSearchInfo(glj); let projectGljModel = new GLJListModel(); let result = await projectGljModel.addList(p_glj,unitFileId,ext);//逐条添加到项目工料机 let typeString = result.type+''; glj.marketPrice = result.unit_price.market_price; glj.adjustPrice = result.unit_price.base_price; glj.basePrice = result.unit_price.base_price; glj.isAdd = result.unit_price.is_add; glj.projectGLJID = result.id; if (typeString.startsWith("2")||typeString=='4'||typeString=='5') {//只有材料类型才显示是否暂估 glj.isEstimate = result.is_evaluate; } } await ration.insertMany(gljList); return gljList; } async function getRationTypeGLJQuantity(projectID) { let rations = await ration.find({'projectID': projectID,'type':3,'deleteInfo': null}, ['ID', 'projectGLJID','quantity']); return rations; } async function changAdjustState(data, rationList) { let stateList = []; for (let r of rationList) { let stateResult = await glj_calculate_facade.calculateQuantity({ projectID: data.query.projectID, rationID: r }, true,true); if(stateResult){ stateList.push({rationID: r, adjustState: stateResult.adjustState,name:stateResult.rationName}); } } return stateList; } async function testError() { throw new Error('test Error'); } function getData(projectID, callback) { ration_glj.find({'projectID': projectID}, (err, datas) => { if (err) { callback(1, '', null); } else { callback(0, consts.projectConst.RATION_GLJ, datas); } }) } function commonCallback(callback, result, err) { if (err) { callback(err, ''); } else { callback(null, result); } }