/** * Created by zhang on 2018/1/26. */ module.exports = { markUpdateProject:markUpdateProject, removeProjectMark:removeProjectMark, updateNodes:updateNodes, calcInstallationFee:calcInstallationFee, saveProperty: saveProperty, getDefaultColSetting: getDefaultColSetting, markProjectsToChange:markProjectsToChange, getBudgetSummayDatas:getBudgetSummayDatas, getGLJSummayDatas:getGLJSummayDatas }; let mongoose = require('mongoose'); let logger = require("../../../logs/log_helper").logger; let projectsModel = mongoose.model('projects'); let async_n = require("async"); let _ = require('lodash'); let ration_model = require('../models/ration'); let bill_model = require('../models/bills'); let consts = require('../models/project_consts'); let projectConsts = consts.projectConst; let ration_glj_model = mongoose.model('ration_glj'); let rationTemplateModel = mongoose.model('ration_template'); let project_glj_model = mongoose.model('glj_list'); let ration_glj_facade = require("../../ration_glj/facade/ration_glj_facade"); const uuidV1 = require('uuid/v1'); const gljUtil = require('../../../public/gljUtil'); let stdColSettingModel = mongoose.model('std_main_col_lib'); let decimal_facade = require('../../main/facade/decimal_facade'); const scMathUtil = require('../../../public/scMathUtil').getUtil(); import fixedFlag from '../../common/const/bills_fixed'; import GLJListModel from "../../glj/models/glj_list_model"; const projectDao = require('../../pm/models/project_model').project; async function calcInstallationFee(data) { let result={}; let billTasks = generateTasks(data.bills,data.useID); let rationTasks = generateTasks(data.ration,data.useID); if(billTasks.length>0){ await bill_model.model.bulkWrite(billTasks); } console.log(rationTasks); if(rationTasks.length>0){ await ration_model.model.bulkWrite(rationTasks); } //如果删除定额,需要删除对应的工料机 if(data.ration.delete.length>0){ let rationIDS = _.map(data.ration.delete,'ID'); await ration_glj_model.deleteMany({projectID: data.ration.delete[0].projectID, rationID: {"$in": rationIDS}});//删除定额工料机 } let rationGLJTasks = []; let updateList = []; if(data.ration.update.length>0){//如果有需要更新的定额工料机 for(let ur of data.ration.update){ for(let g of ur.glj){ let gTasks = { updateOne:{ filter:{ ID:g.ID, projectID:g.projectID }, update :{ quantity:g.quantity, rationItemQuantity:g.rationItemQuantity } } }; rationGLJTasks.push(gTasks); updateList.push(g); } } } if(rationGLJTasks.length>0){ await ration_glj_model.bulkWrite(rationGLJTasks); } let newGljList = []; if(data.ration.add.length>0){//新增的安装子目要增加对应的工料机 for(let nr of data.ration.add){ for(let tkey in nr.glj){ newGljList.push(await addInstallationGLJ(nr.glj[tkey])); } } } if(newGljList.length>0){ await ration_glj_model.insertMany(newGljList); } result.update = updateList; result.add = newGljList; return result; } async function addInstallationGLJ(glj) { glj.ID = uuidV1(); let info = await ration_glj_facade.getInfoFromProjectGLJ(glj); let newRecode = ration_glj_facade.createNewRecord(info); return newRecode; } function generateTasks(data,userID) { let tasks=[]; let deleteInfo={deleted: true, deleteDateTime: new Date(), deleteBy: userID}; if(data.delete && data.delete.length > 0){ for(let bd of data.delete){ //原先是假删除,现在改成真删除 let task = { deleteOne:{ filter:{ ID:bd.ID, projectID:bd.projectID } } }; /* let task={ updateOne:{ filter:{ ID:bd.ID, projectID:bd.projectID }, update :{ deleteInfo:deleteInfo } } };*/ tasks.push(task); } } if(data.add && data.add.length > 0){ for(let n_data of data.add){ let task = { insertOne :{ document:n_data } }; tasks.push(task); } } return tasks; } async function updateNodes(datas){ let nodeGroups = _.groupBy(datas,'type'); let rationTasks = []; let billTasks = []; let rationGLJTasks = []; let projectGLJTasks = []; let projectTasks = []; let rationTemplateTasks = []; let asyncTasks = []; for(let type in nodeGroups){ for(let node of nodeGroups[type]){ if(type == projectConsts.BILLS){ billTasks.push(getTask(node)); }else if(type == projectConsts.RATION){ rationTasks.push(getTask(node)); }else if(type == projectConsts.RATION_GLJ){ rationGLJTasks.push(getTask(node)); }else if(type == projectConsts.PROJECTGLJ){ projectGLJTasks.push(getTask(node,'id')); }else if(type == projectConsts.PROJECT){ projectTasks.push(getTask(node)); }else if(type == projectConsts.RATION_TEMPLATE){ rationTemplateTasks.push(getTask(node)) } } } rationTasks.length>0?asyncTasks.push(ration_model.model.bulkWrite(rationTasks)):''; billTasks.length>0?asyncTasks.push(bill_model.model.bulkWrite(billTasks)):""; rationGLJTasks.length>0?asyncTasks.push(ration_glj_model.bulkWrite(rationGLJTasks)):""; projectGLJTasks.length>0?asyncTasks.push(project_glj_model.bulkWrite(projectGLJTasks)):""; projectTasks.length>0?asyncTasks.push(projectsModel.bulkWrite(projectTasks)):""; rationTemplateTasks.length>0?asyncTasks.push(rationTemplateModel.bulkWrite(rationTemplateTasks)):""; return asyncTasks.length>0?await Promise.all(asyncTasks):""; function getTask(node,idFiled = 'ID') { let task={ updateOne:{ filter:{}, update :_.cloneDeep(node.data) } }; task.updateOne.filter[idFiled] = node.data[idFiled];//现在复制项目也重新生成一个新的ID了,所以ID是唯一的 delete task.updateOne.update[idFiled];//防止误操作 return task; } } /*function updateNodes(datas,callback) { let tasks = []; for(let node of datas){ tasks.push(updateOne(node)) } async_n.parallel(tasks, function(err, results) { if (!err){ callback(0, '', results); } else{ console.log(err); callback(1, 'save project failed'+err.message, null); } }); function updateOne(node) { if(node.type == projectConsts.BILLS){ return function (asCallback) { bill_model.model.findOneAndUpdate({projectID: node.data.projectID, ID: node.data.ID,deleteInfo: null}, node.data,{new: true}, asCallback); } }else if(node.type ==projectConsts.RATION){ return function (asCallback) { ration_model.model.findOneAndUpdate({projectID: node.data.projectID, ID: node.data.ID,deleteInfo: null}, node.data,{new: true}, asCallback); } } } }*/ //data = {feeRateID:111111,projectID:1245}; type = feeRate async function markUpdateProject(data,type) { let query = {deleteInfo:null}; if(type=="feeRate"){//更改了费率 query['property.feeFile.id'] = data.feeRateID; } if(type=="unitFile"){//更改了单价文件 query['property.unitPriceFile.id'] = data.unitFileID;//unitPriceFile } let projects = await projectsModel.find(query); return await markProjectsToChange(projects,type,data.projectID,data.isInclude); } async function markProjectsToChange(projects,type,extProjectID,isInclude){ let tasks=[]; for(let p of projects){ if(isInclude!= true ){ if(extProjectID && p.ID===extProjectID) continue;//排除当前项目 } tasks.push(generateMarkTask(type,p.ID)); } return tasks.length>0 ? await projectsModel.bulkWrite(tasks):null; } async function removeProjectMark(projectID) { return await projectsModel.findOneAndUpdate({ID:projectID},{"$unset":{"changeMark":1}}); } function generateMarkTask(value,projectID) { let task = { updateOne:{ filter:{ ID:projectID }, update:{ changeMark:value } } }; return task } // {projectID: 5, propertyName: 'aaa', propertyValue: 1} function saveProperty(data, callback){ let obj = {}; let pn = 'property.' + data.propertyName; obj[pn] = data.propertyValue; projectsModel.update({"ID": data.projectID}, obj, function (err) { if (err) { logger.err(pn + ' save error: ' + err); callback(err, null) } else { logger.info(pn + ' saved.'); callback('', null); }} ); } async function getDefaultColSetting(libID){ return await stdColSettingModel.findOne({ID: libID, deleted: false}, '-_id main_tree_col'); } async function getBudgetSummayDatas(projectIDs){ try { let projects = []; let names = []; let prjTypeNames = []; let compilationScopes = []; let decimal = null; for(let ID of projectIDs){ projects.push(await getBillsByProjectID(ID)) ; } if(projects.length == 0){ return []; } let mp = projects[0]; names.push(mp.name); prjTypeNames.push(mp.prjTypeName); compilationScopes.push(mp.compilationScope); if(projects.length == 1) decimal = await decimal_facade.getProjectDecimal(projectIDs[0]);//如果只有一个项目,则没走合并的那一步,decimal会为空,从面报错 for(let i = 1;i 0 && b.children.length ==0){ return; }else if(a.children.length == 0 && b.children.length > 0){ a.children = b.children; return; } //=============剩下的是两者都有的情况 for(let s of b.children){ let same = findTheSameItem(a.children,s); same?await mergeItem(same,s,decimal,project):notMatchList.push(s);//如果找到,则合并,找不到就放在未匹配表 } for(let n of notMatchList){ let match = false;//符合插入标记 //对于未匹配的子项,如果是固定清单:第100章至700章清单的子项,要匹配名字中的数字来做排充 if(a.flag == fixedFlag.ONE_SEVEN_BILLS){ for(let i = 0;i< a.children.length;i++){ let m_name = a.children[i].name.replace(/[^0-9]/ig,""); let s_name = n.name.replace(/[^0-9]/ig,""); m_name = parseFloat(m_name); s_name = parseFloat(s_name); if(m_name&&s_name){ if(m_name == s_name){ await mergeItem(a.children[i],n,project); match = true; break; } if(m_name > s_name){//主节点名字中的数字大于被插节点,则被插节点放在主节点前面 a.children.splice(i,0,n); match = true; break; } } } }else {//其它的子项按编号进行排序 for(let i = 0;i< a.children.length ; i++){ let m_code = a.children[i].code; let s_code = n.code; if(m_code && s_code && m_code!=""&&s_code!=""){ if(m_code > s_code){ a.children.splice(i,0,n); match = true; break; } } } } if(match == false)a.children.push(n) //没有插入成功,直接放到最后面 } } function findTheSameItem(main,item) {//编号名称单位三个相同,认为是同一条清单 return _.find(main,function (tem) { return isEqual(tem.code,item.code)&&isEqual(tem.name,item.name)&&isEqual(tem.unit,item.unit); }) } function isEqual(a,b) {//粗略匹配,null undefind "" 认为相等 return getValue(a)==getValue(b); function getValue(t) { if(t==null||t==undefined||t=="") return null; return t; } } async function getBillsByProjectID(projectID){ let roots=[],parentMap={}; let bills = await bill_model.model.find({projectID: projectID}, '-_id');//取出所有清单 let project = await projectsModel.findOne({ID:projectID}); if(!project) throw new Error(`找不到项目:${projectID}`); let projectName = project.name; let author='';//编制人 let auditor='';//审核人 let compilationScope='';//编制范围 let engineering='';//养护类别 if(project.property&&project.property.projectFeature){ for(let f of project.property.projectFeature){ if(f.key == 'author') author = f.value; if(f.key == 'auditor') auditor = f.value; if(f.key =='compilationScope') compilationScope = f.value; if(f.key == 'engineering') engineering = f.value; } } for(let b of bills){ let commonFee =_.find(b._doc.fees,{"fieldName":"common"}); let prices = {}; let quantityMap={}; let unitPrices ={}; if(commonFee&&commonFee.totalFee) prices[projectName] = commonFee.totalFee; if (commonFee&&commonFee.unitFee) unitPrices[projectName] = commonFee.unitFee; quantityMap[projectName] = b.quantity; let flagIndex = _.find(b._doc.flags,{'fieldName':'fixed'}); let doc = {ID:b.ID,name:b.name,code:b.code,unit:b.unit,projectID:b.projectID, ParentID:b.ParentID,NextSiblingID:b.NextSiblingID,unitPrices:unitPrices,quantity:b.quantity,prices:prices,quantityMap:quantityMap,flag:flagIndex?flagIndex.flag:-99,remark:b.remark};//选取有用字段 if(b.ParentID == -1) roots.push(doc); parentMap[b.ParentID]?parentMap[b.ParentID].push(doc):parentMap[b.ParentID]=[doc]; }//设置子节点 for(let r of roots){ setChildren(r,parentMap,1); } roots = sortChildren(roots); return {name:projectName,roots:roots,author:author,auditor:auditor,compilationScope:compilationScope,ParentID:project.ParentID,prjTypeName:engineering} } function setChildren(bill,parentMap,level) { let children = parentMap[bill.ID]; if(children){ for(let c of children){ setChildren(c,parentMap,level+1) } bill.children = children; }else { bill.children = []; } } function sortChildren(lists) { let IDMap ={},nextMap = {}, firstNode = null,newList=[]; for(let l of lists){ if(l.children&&l.children.length > 0) l.children = sortChildren(l.children);//递规排序 IDMap[l.ID] = l; if(l.NextSiblingID!=-1) nextMap[l.NextSiblingID] = l; } for(let t of lists){ if(!nextMap[t.ID]){ //如果在下一节点映射没找到,则是第一个节点 firstNode = t; break; } } if(firstNode){ newList.push(firstNode); delete IDMap[firstNode.ID]; setNext(firstNode,newList); } //容错处理,如果链断了的情况,直接添加到后面 for(let key in IDMap){ if(IDMap[key]) newList.push(IDMap[key]) } return newList; function setNext(node,array) { if(node.NextSiblingID != -1){ let next = IDMap[node.NextSiblingID]; if(next){ array.push(next); delete IDMap[next.ID]; setNext(next,array); } } } } async function getGLJSummayDatas(projectIDs) { let projects = []; let names = []; let prjTypeNames = []; try { for(let ID of projectIDs){ projects.push(await getProjectData(ID)) ; } if(projects.length == 0){ return []; } let mp = projects[0]; for(let p of projects){ names.push(p.name); prjTypeNames.push(p.prjTypeName); p.gljList = await getProjectGLJData(p.ID,p.unitPriceFileId,mp.property); } let mList = mergeGLJ(mp,projects,names,prjTypeNames); mList = gljUtil.sortProjectGLJ(mList,_); let summaryGLJDatas = getSummaryGLJDatas(mList,mp.property.decimal,names,prjTypeNames); let parentProject = await projectsModel.findOne({ID:mp.ParentID}); let result = { prj: {}, SummaryAudit:{ "name": parentProject?parentProject.name:"", "编制": mp.author, "复核": mp.auditor, "编制范围":mp.compilationScope }, SummaryAuditDetail:summaryGLJDatas }; return result; }catch (e){ console.log(e); } } function getSummaryGLJDatas(gljList,decimal,nameList,prjTypeNames) { let datas = [],qdecimal = decimal.glj.quantity,process = decimal.process; for(let tem of gljList){ let d = { code:tem.code, name:tem.name, type:tem.type, unit:tem.unit, specs:tem.specs, marketPrice:tem.marketPrice, prjNames:nameList, prjTypeNames:prjTypeNames, quantityList:[] }; let totalQuantity = 0; for(let n of nameList){ let q = tem.quantityMap[n]?scMathUtil.roundForObj(tem.quantityMap[n],qdecimal):0; totalQuantity = scMathUtil.roundForObj(q+totalQuantity,process); d.quantityList.push(q); } d.totalQuantity = scMathUtil.roundForObj(totalQuantity,qdecimal); datas.push(d); } return datas; } function mergeGLJ(mp,projects) { let gljMap = {},gljList=[]; for(let g of mp.gljList){ g.quantityMap={}; g.quantityMap[mp.name] = g.quantity; gljMap[gljUtil.getIndex(g)] = g; gljList.push(g); } for(let i = 1;i