|
|
@@ -1,6 +1,18 @@
|
|
|
/**
|
|
|
* 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
|
|
|
+};
|
|
|
+
|
|
|
let mongoose = require('mongoose');
|
|
|
let logger = require("../../../logs/log_helper").logger;
|
|
|
let projectsModel = mongoose.model('projects');
|
|
|
@@ -17,17 +29,12 @@ 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';
|
|
|
+const projectDao = require('../../pm/models/project_model').project;
|
|
|
+
|
|
|
|
|
|
-module.exports = {
|
|
|
- markUpdateProject:markUpdateProject,
|
|
|
- removeProjectMark:removeProjectMark,
|
|
|
- updateNodes:updateNodes,
|
|
|
- calcInstallationFee:calcInstallationFee,
|
|
|
- saveProperty: saveProperty,
|
|
|
- getDefaultColSetting: getDefaultColSetting,
|
|
|
- markProjectsToChange:markProjectsToChange,
|
|
|
- getBudgetSummayDatas:getBudgetSummayDatas
|
|
|
-};
|
|
|
|
|
|
async function calcInstallationFee(data) {
|
|
|
let result={};
|
|
|
@@ -275,41 +282,261 @@ async function getDefaultColSetting(libID){
|
|
|
}
|
|
|
|
|
|
async function getBudgetSummayDatas(projectIDs){
|
|
|
- let projects = [];
|
|
|
- for(let ID of projectIDs){
|
|
|
- projects.push(await getBillsByProjectID(ID)) ;
|
|
|
+ try {
|
|
|
+ let projects = [];
|
|
|
+ let names = [];
|
|
|
+ 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);
|
|
|
+ for(let i = 1;i<projects.length;i++){
|
|
|
+ names.push(projects[i].name);
|
|
|
+ decimal = await mergeProject(mp.roots,projects[i].roots)
|
|
|
+ }
|
|
|
+ let SummaryAuditDetail = getReportData(names,mp.roots,decimal);
|
|
|
+ let parentProject = await projectsModel.findOne({ID:mp.ParentID});
|
|
|
+ let result = {
|
|
|
+ prj: {},
|
|
|
+ SummaryAudit:{
|
|
|
+ "name": parentProject?parentProject.name:"",
|
|
|
+ "编制": mp.author,
|
|
|
+ "复核": mp.auditor
|
|
|
+ },
|
|
|
+ SummaryAuditDetail:SummaryAuditDetail
|
|
|
+ }
|
|
|
+ console.log(JSON.stringify(result));
|
|
|
+ return result;
|
|
|
+ }catch (e){
|
|
|
+ console.log(e)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function getReportData(nameList,items,decimal) {
|
|
|
+ let datas = [],totalItem = null;
|
|
|
+ setChildrenDatas(items,datas);
|
|
|
+ for(let d of datas){
|
|
|
+ if(d.billsTtlPrices){
|
|
|
+ d['各项费用比例'] = scMathUtil.roundForObj(d.billsTtlPrices/totalItem.billsTtlPrices * 100,2)
|
|
|
+ }
|
|
|
+ d['prjNames'] = nameList;
|
|
|
+ }
|
|
|
+ return datas;
|
|
|
+
|
|
|
+
|
|
|
+ function setChildrenDatas(children,arr) {
|
|
|
+ for(let c of children){
|
|
|
+ arr.push(getBillDatas(c));
|
|
|
+ setChildrenDatas(c.children,arr);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function getBillDatas(bills) {
|
|
|
+ let tem = {
|
|
|
+ billsName:bills.name,
|
|
|
+ billsCode:bills.code,
|
|
|
+ billsUnit:bills.unit,
|
|
|
+ billsTtlAmt:bills.quantity,
|
|
|
+ billsPrices:[],
|
|
|
+ billsMemos:bills.remark
|
|
|
+ };
|
|
|
+ let total = 0;
|
|
|
+ for(let n of nameList){
|
|
|
+ if(bills.prices[n]){
|
|
|
+ let p = scMathUtil.roundForObj(bills.prices[n],decimal.bills.totalPrice);
|
|
|
+ tem.billsPrices.push(p);
|
|
|
+ total = scMathUtil.roundForObj(p+total,decimal.process);
|
|
|
+ }else {
|
|
|
+ tem.billsPrices.push(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ tem.billsTtlPrices = scMathUtil.roundForObj(total,decimal.bills.totalPrice);
|
|
|
+
|
|
|
+ if(tem.billsTtlAmt) tem['技术经济指标'] = scMathUtil.roundForObj(tem.billsTtlPrices/tem.billsTtlAmt,2);
|
|
|
+ if(bills.flag == fixedFlag.TOTAL_COST) totalItem = tem;
|
|
|
+ return tem
|
|
|
}
|
|
|
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
+async function mergeProject(main,sub) {//合并两个项目
|
|
|
+ let decimal = await decimal_facade.getProjectDecimal(main[0].projectID);
|
|
|
+ let project = await projectsModel.findOne({ID:main[0].projectID});
|
|
|
+ let notMatchList = [];
|
|
|
+ for(let s of sub){
|
|
|
+ //先找有没有相同的大项费用
|
|
|
+ let same = findTheSameItem(main,s);
|
|
|
+ same?await mergeItem(same,s,decimal,project._doc):notMatchList.push(s);//如果找到,则合并,找不到就放在未匹配表
|
|
|
+ }
|
|
|
+ for(let n of notMatchList){
|
|
|
+ main.push(n);
|
|
|
+ }
|
|
|
|
|
|
+ return decimal;
|
|
|
+}
|
|
|
+
|
|
|
+async function mergeItem(a,b,decimal,project) {
|
|
|
+ let bqDecimal = await decimal_facade.getBillsQuantityDecimal(a.projectID,a.unit,project);
|
|
|
+ a.quantity = a.quantity?scMathUtil.roundForObj(a.quantity,bqDecimal):0;
|
|
|
+ b.quantity = b.quantity?scMathUtil.roundForObj(b.quantity,bqDecimal):0;
|
|
|
+ a.quantity = scMathUtil.roundForObj(a.quantity+b.quantity,decimal.process);
|
|
|
+ for(let name in b.prices){
|
|
|
+ a.prices[name] = b.prices[name];
|
|
|
+ }
|
|
|
+ await mergeChildren(a,b,decimal,project);
|
|
|
+}
|
|
|
+
|
|
|
+async function mergeChildren(a,b,decimal,project) {
|
|
|
+ let notMatchList = [];
|
|
|
+ if(a.children.length > 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 items = [],roots=[],parentMap={};
|
|
|
+ let roots=[],parentMap={};
|
|
|
let bills = await bill_model.model.find({projectID: projectID}, '-_id');//取出所有清单
|
|
|
let project = await projectsModel.findOne({ID:projectID});
|
|
|
- let projectName = project?project.name:"";
|
|
|
+ if(!project) throw new Error(`找不到项目:${projectID}`);
|
|
|
+ let projectName = project.name;
|
|
|
+ let author='';//编制人
|
|
|
+ let auditor='';//审核人
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
for(let b of bills){
|
|
|
- items.push(b._doc);
|
|
|
- if(b.parentID == -1) roots.push(b._doc);
|
|
|
- parentMap[b.parentID]?parentMap[b.parentID].push[b._doc]:parentMap[b.parentID]=[b._doc];
|
|
|
- }//设置子节点+排序
|
|
|
+ let commonFee =_.find(b._doc.fees,{"fieldName":"common"});
|
|
|
+ let prices = {};
|
|
|
+ if(commonFee&&commonFee.totalFee) prices[projectName] = commonFee.totalFee;
|
|
|
+ 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,quantity:b.quantity,prices:prices,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)
|
|
|
+ setChildren(r,parentMap,1);
|
|
|
}
|
|
|
+ roots = sortChildren(roots);
|
|
|
+ return {name:projectName,roots:roots,author:author,auditor:auditor,ParentID:project.ParentID}
|
|
|
}
|
|
|
|
|
|
-function setChildren(bill,parentMap) {
|
|
|
+function setChildren(bill,parentMap,level) {
|
|
|
let children = parentMap[bill.ID];
|
|
|
- let childrenMap = {};
|
|
|
- let firstNode = null;
|
|
|
if(children){
|
|
|
for(let c of children){
|
|
|
- childrenMap[c.ID] = c;
|
|
|
- setChildren(c,parentMap)
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|