ration_facade.js 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259
  1. /**
  2. * Created by zhang on 2018/2/9.
  3. */
  4. module.exports = {
  5. replaceRations: replaceRations,
  6. addNewRation:addNewRation,
  7. updateMaterialRation:updateMaterialRation,
  8. addMaterialRation:addMaterialRation,
  9. addMultiRation: addMultiRation,
  10. getSameSectionRations:getSameSectionRations,
  11. getExtendData:getExtendData,
  12. getDefaultProgramID:getDefaultProgramID,
  13. deleteSubListByQuery:deleteSubListByQuery,
  14. updateCoeAdjust:updateCoeAdjust,
  15. getUnitPriceData:getUnitPriceData,
  16. setIDfromCounter:setIDfromCounter,
  17. getNewProjectGLJFromMissMixratio:getNewProjectGLJFromMissMixratio
  18. };
  19. let mongoose = require('mongoose');
  20. import SearchDao from '../../complementary_ration_lib/models/searchModel';
  21. import GLJListModel from "../../glj/models/glj_list_model";
  22. import e from 'express';
  23. const scMathUtil = require('../../../public/scMathUtil').getUtil();
  24. let gljUtil = require('../../../public/gljUtil');
  25. let ration_glj_facade = require("../../ration_glj/facade/ration_glj_facade");
  26. let glj_calculate_facade = require("../../ration_glj/facade/glj_calculate_facade");
  27. let quantity_detail = require("../facade/quantity_detail_facade");
  28. let ration_glj = mongoose.model('ration_glj');
  29. let ration_coe = mongoose.model('ration_coe');
  30. let ration_model = require('../models/ration');
  31. let bill_model = require('../models/bills');
  32. let decimal_facade = require('./decimal_facade');
  33. let installationFeeModel = mongoose.model("installation_fee");
  34. let rationInstallationModel = mongoose.model('ration_installation');
  35. let rationTemplateModel = mongoose.model('ration_template');
  36. const uuidV1 = require('uuid/v1');
  37. let std_glj_lib_gljList_model = mongoose.model('std_glj_lib_gljList');
  38. let complementary_glj_model = mongoose.model('complementary_glj_lib');
  39. let rationItemModel = mongoose.model("std_ration_lib_ration_items");
  40. let complementaryRationModel = mongoose.model('complementary_ration_items');
  41. let freightCalcModel = mongoose.model('freight_calc');
  42. let originaltCalcModel = mongoose.model('original_calc');
  43. let coeMolde = mongoose.model('std_ration_lib_coe_list');
  44. let compleCoeModel = mongoose.model('complementary_ration_coe_list');
  45. let projectGLJModel = mongoose.model("glj_list");
  46. let mixRatioModel = mongoose.model("mix_ratio");
  47. let complementaryGljLibModel = mongoose.model('complementary_glj_lib');
  48. let counterModel = mongoose.model('counter');
  49. let _= require('lodash');
  50. const projectDao = require('../../pm/models/project_model').project;
  51. let projectModel = mongoose.model('projects');
  52. let unitPriceModel = mongoose.model('unit_price');
  53. let unitPriceFileModel = mongoose.model('unit_price_file');
  54. let vvTaxModel = mongoose.model("std_vehicleVesselTax_items");
  55. const fs = require('fs');
  56. async function addNewRation(data,compilation) {
  57. let query = data.itemQuery;
  58. let stdRation = null;
  59. let startTime = +new Date();
  60. if(query){
  61. let searchDao = new SearchDao();
  62. stdRation = await searchDao.getRationItem(query.userID, compilation._id, [query.rationRepId],query.code, query.ID);
  63. //data.newData.code = query.code;
  64. }
  65. let stdRationTime = +new Date();
  66. console.log("取std定额时间-------------------------------"+(stdRationTime - startTime));
  67. if(data.brUpdate.length>0){
  68. await updateSerialNo(data.brUpdate);
  69. }
  70. let newRation =await insertNewRation(data.newData,data.defaultLibID,stdRation,data.calQuantity);
  71. let addRationGLJTime = +new Date();
  72. console.log("插入新定额时间-------------------------------"+(addRationGLJTime - stdRationTime));
  73. if(stdRation){
  74. return await addRationSubList(stdRation,newRation,data.needInstall,compilation);
  75. }else {
  76. return {ration:newRation};
  77. }
  78. }
  79. async function updateMaterialRation(data,compilation){
  80. let result = {};
  81. switch (data.actionType){
  82. case "add":
  83. result = await addMaterialRation(data,compilation);
  84. break;
  85. case "delete":
  86. result = await deleteMaterialRation(data);
  87. case "update":
  88. result = await modifyMaterialRation(data,compilation);
  89. }
  90. return result;
  91. }
  92. async function deleteMaterialRation(data) {
  93. let model = data.type == "freight"?freightCalcModel:originaltCalcModel;
  94. await model.update(
  95. {ID:data.parentID},
  96. { $pull: { rations: { ID: data.rationID},ration_gljs:{rationID:data.rationID} } },
  97. { multi: true }
  98. );
  99. return data;
  100. }
  101. async function modifyMaterialRation(data,compilation) {
  102. let model = data.type == "freight"?freightCalcModel:originaltCalcModel;
  103. if(data.field == "code"){
  104. let [newRation,ration_gljs,projectGLJList] = await getNewMaterialRationDatas(data,compilation);
  105. let quantity = data.rations[data.row].quantity;
  106. newRation.quantity = quantity;
  107. data.rations[data.row] = newRation;
  108. _.remove(data.ration_gljs,{rationID:data.rationID});
  109. data.ration_gljs = data.ration_gljs.concat(ration_gljs);
  110. await model.update({'ID':data.parentID},{rations:data.rations,ration_gljs:data.ration_gljs});
  111. return {ration:newRation,ration_gljs:ration_gljs,projectGLJList:projectGLJList}
  112. }else {
  113. let doc = {},pre = "rations.$.";
  114. let field = pre+data.field;
  115. doc[field] = data.value;
  116. if(data.ext){
  117. for(let key in data.ext){
  118. doc[pre+key] = data.ext[key];
  119. }
  120. }
  121. if(data.ration_gljs){
  122. let tasks = [];
  123. for(let g of data.ration_gljs){
  124. tasks.push({updateOne: {filter: {'ID':data.parentID,'ration_gljs.ID':g.ID}, update: {"ration_gljs.$.quantity":g.quantity}}})
  125. }
  126. await model.bulkWrite(tasks);
  127. }
  128. return await model.update({'ID':data.parentID,'rations.ID':data.rationID},doc);
  129. }
  130. }
  131. async function addMaterialRation(data,compilation) {
  132. let [newRation,ration_gljs,projectGLJList] = await getNewMaterialRationDatas(data,compilation);
  133. let model = data.type == "freight"?freightCalcModel:originaltCalcModel;
  134. await model.update({ID:data.parentID},{$push:{rations:newRation,ration_gljs:{$each:ration_gljs}}});
  135. return{ration:newRation,ration_gljs:ration_gljs,projectGLJList:projectGLJList};
  136. }
  137. async function getNewMaterialRationDatas(data,compilation){
  138. let searchDao = new SearchDao();
  139. let stdRation = await searchDao.getRationItem(data.userID, compilation._id, data.rationRepIds,data.code);
  140. if(!stdRation) throw "找不到指定的定额!";//new Error("找不到指定的定额!");
  141. let newRation = await createNewMaterialRation(stdRation,data.quantityDecimal,data.projectID);
  142. let [ration_gljs,projectGLJList] = await addRationGLJ(stdRation,newRation,compilation,true,data.connect_key);
  143. return [newRation,ration_gljs,projectGLJList];
  144. }
  145. async function createNewMaterialRation(std,quantityDecimal,projectID){
  146. let newData = {};
  147. newData.ID = uuidV1();
  148. newData.projectID = projectID;
  149. newData.code = std.code;
  150. newData.name = std.name;
  151. newData.caption = std.caption;
  152. newData.unit = std.unit;
  153. newData.libID = std.rationRepId;
  154. newData.stdID = std.ID;
  155. newData.quantity=scMathUtil.roundForObj(1 / FilterNumberFromUnit(std.unit),quantityDecimal);
  156. newData.from = std.type === 'complementary' ? 'cpt' : 'std';
  157. newData.rationAssList =await createRationAss(std,true);
  158. return newData;
  159. }
  160. async function addMultiRation(datas,compilation) {
  161. /* let rst = [];
  162. for(let data of datas){
  163. let r = await addNewRation(data,compilation);
  164. rst.push(r);
  165. }
  166. return rst; */
  167. const task = [];
  168. for (const data of datas) {
  169. task.push(addNewRation(data, compilation));
  170. }
  171. return await Promise.all(task);
  172. }
  173. async function getSameSectionRations(data,userId,compilationId){
  174. //let userId
  175. //要先根据定额获取所属章节的ID
  176. let from = data.from; //定额类型,是标准的还是用户定义的
  177. let code = data.code;
  178. let libID = data.libID;
  179. let sectionId,rations=[];
  180. if(from == 'std'){
  181. let ration = await rationItemModel.findOne({rationRepId:libID,code:code},['sectionId']);
  182. sectionId = ration? ration.sectionId:null;
  183. }else {
  184. let ration = await complementaryRationModel.findOne({userId:userId,compilationId: compilationId,code:code},['sectionId']);
  185. sectionId = ration?ration.sectionId:null;
  186. }
  187. if(sectionId){
  188. if (from == 'std') {
  189. rations = await rationItemModel.find({sectionId: sectionId});
  190. } else {
  191. rations = await complementaryRationModel.find({userId: userId, sectionId: sectionId});
  192. }
  193. rations = _.sortBy(rations,'code');
  194. }
  195. return rations
  196. }
  197. async function updateSerialNo(serialNoUpdate){
  198. let tasks=[];
  199. for(let data of serialNoUpdate){
  200. let task={
  201. updateOne:{
  202. filter:{
  203. ID:data.ID,
  204. projectID:data.projectID
  205. },
  206. update :{
  207. serialNo:data.serialNo
  208. }
  209. }
  210. };
  211. tasks.push(task);
  212. }
  213. await ration_model.model.bulkWrite(tasks);
  214. }
  215. async function insertNewRation(newData,defaultLibID,std,calQuantity) {//插入新的定额
  216. let startTime = +new Date();
  217. if(std){
  218. newData.code = std.code;
  219. newData.name = std.name;
  220. newData.caption = std.caption;
  221. newData.unit = std.unit;
  222. newData.libID = std.rationRepId;
  223. newData.stdID = std.ID;
  224. newData.content = std.jobContent;
  225. newData.annotation = std.annotation;
  226. if (std.chapter) {
  227. newData.comments = std.chapter.explanation;
  228. newData.ruleText = std.chapter.ruleText;
  229. }
  230. newData.prefix = '';
  231. newData.from = std.type === 'complementary' ? 'cpt' : 'std';
  232. if(defaultLibID !== std.rationRepId){//借
  233. newData.prefix = '借';
  234. }
  235. else if(std.rationRepId === defaultLibID && newData.from === 'cpt') {
  236. newData.prefix = '补';
  237. }
  238. if(std.feeType == undefined || std.feeType == null || std.feeType ==''){//定额取费专业为空的情况下,取项目属性中的定额取费专业ID
  239. newData.programID = await getProgramForProject(newData.projectID);
  240. }else {
  241. newData.programID = std.feeType;
  242. }
  243. newData.rationAssList =await createRationAss(std);
  244. // calculate ration Quantity
  245. }
  246. if(calQuantity){
  247. await CalculateQuantity(newData,newData.billsItemID,newData.projectID);
  248. }
  249. let addRationGLJTime = +new Date();
  250. console.log("计算消耗量时间-------------------------------"+(addRationGLJTime - startTime));
  251. await ration_model.model.insertMany([newData]);
  252. return newData;
  253. /*ration_model.model.create(newData);
  254. return newData;*/
  255. }
  256. async function replaceRations(userID,data,compilation) {
  257. let searchDao = new SearchDao();
  258. let recodes = [];
  259. for(let recode of data.nodeInfo){
  260. let stdRation = await searchDao.getRationItem(userID,compilation._id,data.libIDs,recode.newCode, null);
  261. let newRecode = await replaceRation(recode,stdRation,data.defaultLibID,data.projectID,data.calQuantity,compilation,data.cleanzmhs);
  262. if(newRecode){
  263. recodes.push(newRecode);
  264. }else {
  265. break;
  266. }
  267. }
  268. return recodes;
  269. }
  270. async function getDefaultProgramID(data) {
  271. let searchDao = new SearchDao();
  272. let programID;
  273. let std = await searchDao.getRationItem(data.userID,data.compilationId,[data.libID],data.code, null);
  274. if(std == null||std ==undefined || std.feeType == undefined || std.feeType == null || std.feeType ==''){//定额取费专业为空的情况下,取项目属性中的定额取费专业ID
  275. programID = await getProgramForProject(data.projectID);
  276. }else {
  277. programID = std.feeType;
  278. }
  279. return programID;
  280. }
  281. async function replaceRation(nodeInfo,stdRation,defaultLibID,projectID,calQuantity,compilation,cleanzmhs) {
  282. if(nodeInfo.newCode == null||nodeInfo.newCode ==""){//说明是删除编号,则要变成一条空定额
  283. await deleRationSubRecode(projectID,nodeInfo.ID);//删除定额下挂的各种数据,如定额工料机等
  284. return await setEmptyRation(projectID,nodeInfo.ID);
  285. }else if(stdRation){
  286. await deleRationSubRecode(projectID,nodeInfo.ID,cleanzmhs);//删除定额下挂的各种数据,如定额工料机等
  287. let newRation = await updateRation(stdRation,defaultLibID,nodeInfo.ID,nodeInfo.billsItemID,projectID,calQuantity,cleanzmhs);//生成并插入新的定额
  288. return await addRationSubList(stdRation,newRation,nodeInfo.needInstall,compilation,cleanzmhs);
  289. }else {
  290. return null;
  291. }
  292. }
  293. async function addRationSubList(stdRation,newRation,needInstall,compilation,cleanzmhs=false) {
  294. let startTime = +new Date();
  295. let [ration_gljs,projectGLJList] = await addRationGLJ(stdRation,newRation,compilation);
  296. let addRationGLJTime = +new Date();
  297. console.log("添加定额工料机时间-----"+(addRationGLJTime - startTime));
  298. let ration_coes = await addRationCoe(stdRation,newRation,compilation);
  299. let addRationCoeTime = +new Date();
  300. console.log("添加定额coe时间-----"+(addRationCoeTime - addRationGLJTime));
  301. let ration_installations = [];
  302. let ration_template = [];
  303. if(cleanzmhs == false){//清除子目换算即cleanzmh==true时 模板子目、安装增加费不用恢复成标准的
  304. if(needInstall && stdRation.type == 'std'){//只有标准的定额才有安装增加费,补充的定额没有安装增加费
  305. ration_installations = await addRationInstallFee(stdRation,newRation);
  306. }
  307. let addRationInstallFeeTime = +new Date();
  308. console.log("添加定额install时间-----"+(addRationInstallFeeTime - addRationCoeTime));
  309. //添加定额模板子目
  310. ration_template = await addRationTemplate(stdRation,newRation);
  311. }
  312. return {ration:newRation,ration_gljs:ration_gljs,ration_coes:ration_coes,ration_installations:ration_installations,ration_templates:ration_template?[ration_template]:[],projectGLJList:projectGLJList};
  313. }
  314. async function addRationInstallFee(std,newRation) {
  315. let install_fee_list = [];
  316. if(std.hasOwnProperty('rationInstList') && std.rationInstList.length > 0){
  317. let installFee = await installationFeeModel.findOne({'projectID': newRation.projectID});
  318. if(!installFee) return;//如果没有找到项目对应的安装增加费,则不添加
  319. for(let ri of std.rationInstList){
  320. let feeItem = _.find(installFee.installFeeItem,{'ID':ri.feeItemId});
  321. let section = _.find(installFee.installSection,{'ID':ri.sectionId});
  322. if(feeItem&&section){
  323. let tem_r_i = {
  324. libID:installFee.libID,
  325. projectID:newRation.projectID,
  326. rationID:newRation.ID,
  327. feeItemId:feeItem.ID,
  328. sectionId:section.ID,
  329. itemName:feeItem.feeItem,
  330. feeType:feeItem.feeType,
  331. sectionName:section.name,
  332. unifiedSetting:1,
  333. ruleId:''
  334. };
  335. if(feeItem.isCal==1&&section.feeRuleId&&section.feeRuleId!=''){//勾选记取时并且有规则ID时才读取
  336. let feeRule = _.find(installFee.feeRule,{'ID':section.feeRuleId});
  337. if(feeRule){
  338. tem_r_i.ruleId = feeRule.ID;
  339. }
  340. }
  341. tem_r_i.ID = uuidV1();
  342. install_fee_list.push(tem_r_i);
  343. }
  344. }
  345. if(install_fee_list.length>0){
  346. await rationInstallationModel.insertMany(install_fee_list);
  347. }
  348. }
  349. return install_fee_list;
  350. }
  351. async function addRationTemplate(std,newRation) {
  352. let templateList = [];
  353. if(std.hasOwnProperty('rationTemplateList') && std.rationTemplateList.length > 0){
  354. for(let tem of std.rationTemplateList){
  355. let re_ration = await rationItemModel.findOne({rationRepId:std.rationRepId,ID:tem.rationID});
  356. if(re_ration){
  357. let template = {
  358. billID:"",
  359. fxID:"",
  360. quantity:"0",
  361. coe:"0"
  362. };
  363. template.code = re_ration.code;
  364. template.name = re_ration.name;
  365. template.type = tem.type;
  366. template.unit = re_ration.unit;
  367. template.billsLocation = tem.billsLocation;
  368. template.defaultLocation = tem.billsLocation;
  369. templateList.push(template)
  370. }
  371. }
  372. }
  373. if(templateList.length > 0){
  374. let ration_template = {};
  375. ration_template.ID = uuidV1();
  376. ration_template.projectID = newRation.projectID;
  377. ration_template.rationID = newRation.ID;
  378. ration_template.createLocation = 1; //默认模板子目分别放在措施项目下
  379. ration_template.templateList = templateList;
  380. await rationTemplateModel.create(ration_template);
  381. return ration_template;
  382. }
  383. return null;
  384. }
  385. async function addRationCoe(std,newRation,compilation) {
  386. let ration_coe_list = [];
  387. let seq = 0;
  388. let stdCoeIDs = [];
  389. let coeMap={}
  390. if(std.hasOwnProperty('rationCoeList')&&std.rationCoeList.length>0){//添加标准库的工料机
  391. for(let sub of std.rationCoeList){
  392. let libCoe;
  393. if (std.type === 'std') {
  394. libCoe = await coeMolde.findOne({'libID':std.rationRepId,'ID':sub.ID,"$or": [{"isDeleted": null}, {"isDeleted": false}]});//std.rationRepId;
  395. } else {
  396. libCoe = await compleCoeModel.findOne({ID: sub.ID, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
  397. }
  398. if(libCoe){
  399. let newCoe = {};
  400. newCoe.ID = uuidV1();
  401. newCoe.coeID = sub.ID;
  402. newCoe.seq = seq;
  403. newCoe.name = libCoe.name;
  404. newCoe.content = libCoe.content;
  405. newCoe.original_code = libCoe.original_code;
  406. newCoe.option_codes = libCoe.option_codes;
  407. newCoe.option_list = libCoe.option_list;
  408. newCoe.isAdjust=0;
  409. newCoe.coes = libCoe.coes;
  410. newCoe.rationID = newRation.ID;
  411. newCoe.projectID = newRation.projectID;
  412. seq++;
  413. ration_coe_list.push(newCoe);
  414. }
  415. }
  416. }
  417. let lastCoe = await getCustomerCoe(newRation.projectID,newRation.ID,seq,compilation);
  418. ration_coe_list.push(lastCoe);
  419. await ration_coe.insertMany(ration_coe_list);
  420. return ration_coe_list;
  421. }
  422. function getCustomerCoeData() {
  423. var coeList = [
  424. {amount:1, operator:'*', gljCode:null, coeType:'定额'},
  425. { amount:1, operator:'*', gljCode:null, coeType:'人工'},
  426. { amount:1, operator:'*', gljCode:null, coeType:'材料'},
  427. { amount:1, operator:'*', gljCode:null, coeType:'机械'},
  428. /* { amount:1, operator:'*', gljCode:null, coeType:'主材'},*/
  429. { amount:1, operator:'*', gljCode:null, coeType:'设备'}
  430. ];
  431. return coeList;
  432. };
  433. async function getCustomerCoe(projectID,rationID,seq,compilation){//取自定义乘系数,根据编办不同,内容可能不同
  434. //生成默认的自定义乘系数
  435. let lastCoe ={
  436. coeID:-1,
  437. name : '自定义系数',
  438. content:'人工×1,材料×1,机械×1,设备×1',//主材×1,
  439. isAdjust:1,
  440. seq:seq,
  441. rationID : rationID,
  442. projectID : projectID
  443. };
  444. lastCoe.ID = uuidV1();
  445. lastCoe.coes = getCustomerCoeData();
  446. try {
  447. //查看编办中有没有重写路径 -- 养护中暂时没用到
  448. /* if(compilation.overWriteUrl && compilation.overWriteUrl!=""){
  449. let overWrite = require("../../.."+compilation.overWriteUrl);
  450. if(overWrite.getCusCoeContent) lastCoe.content = overWrite.getCusCoeContent();
  451. if(overWrite.getCustomerCoeData) lastCoe.coes = overWrite.getCustomerCoeData();
  452. } */
  453. return lastCoe
  454. }catch (err){
  455. console.log("读取自定义系数重写文件失败");
  456. console.log(err.message);
  457. return lastCoe
  458. }
  459. }
  460. //对于多单价,多组成物消耗量的编办,通过这个方法获取单价、组成物消耗量的字段,
  461. function getExtendData(property,compilation) {
  462. return projectDao.getExtendData(property,compilation);
  463. }
  464. async function addRationGLJ(std,newRation,compilation,isMaterial,connect_key) {
  465. let newRationGLJList = [];
  466. let rationGLJShowList = [];
  467. let projectGLJList = [];
  468. let gljKeyMap = {};
  469. let mixRatioMap={};
  470. let gljCodes=[];
  471. let unitPriceFileId = 0;
  472. let property = await projectDao.getProjectProperty(newRation.projectID);
  473. if(property){
  474. unitPriceFileId = property.unitPriceFile !== undefined ? property.unitPriceFile.id : 0;
  475. }
  476. let ext = getExtendData(property,compilation);
  477. let first = +new Date();
  478. if(std.hasOwnProperty('rationGljList') && std.rationGljList.length > 0){
  479. let stdGLJID =[];//标准工料机ID数组
  480. let cptGLJID=[];//补充工料机ID数组
  481. //let stdGLJID = _.map(std.rationGljList,'gljId');
  482. for(let tem_g of std.rationGljList){
  483. if(tem_g.type == 'complementary'){
  484. cptGLJID.push(tem_g.gljId);
  485. }else {
  486. stdGLJID.push(tem_g.gljId);
  487. }
  488. }
  489. let stdGLJList = stdGLJID.length > 0 ? await std_glj_lib_gljList_model.find({'ID':{'$in':stdGLJID}}).lean():[];//速度优化-------先一次性取出所有的工料机列表
  490. let stdGLJMap = _.indexBy(stdGLJList, 'ID');
  491. let cptGLJList = cptGLJID.length > 0 ? await complementary_glj_model.find({'userId':std.userId,'ID':{'$in':cptGLJID}}).lean():[];
  492. let cptGLJMap = _.indexBy(cptGLJList, 'ID');
  493. let stdGLJMapTime = +new Date();
  494. console.log("找到工料机映射表时间-------------------------------"+(stdGLJMapTime - first));
  495. if(isMaterial == true){//材料计算添加时要先检查
  496. for(let sub of std.rationGljList){
  497. let t_g = getStdGlj(sub,stdGLJMap,cptGLJMap,{},ext);
  498. if(t_g && connect_key == gljUtil.getIndex(t_g)) throw `本定额中包含工料机${t_g.code},与当前工料机编号相同,添加定额失败`;
  499. }
  500. }
  501. for(let sub of std.rationGljList){
  502. let newGLJ = {};
  503. let proportion = sub.proportion || 0;
  504. newGLJ.ID = uuidV1();
  505. newGLJ.projectID = newRation.projectID;
  506. newGLJ.GLJID = sub.gljId;
  507. newGLJ.rationID = newRation.ID;
  508. newGLJ.billsItemID = newRation.billsItemID;
  509. newGLJ.rationItemQuantity = sub.consumeAmt;
  510. newGLJ.quantity = sub.consumeAmt;
  511. newGLJ.glj_repository_id = std.rationRepId;
  512. newGLJ.rationProportion = proportion;
  513. newGLJ.adjustProportion = proportion;
  514. let std_glj = getStdGlj(sub,stdGLJMap,cptGLJMap,{},ext);
  515. if(std_glj){
  516. ration_glj_facade.setPropertyFromStd(newGLJ,std_glj);
  517. let tindex = getIndex(newGLJ);
  518. if(std_glj.component && std_glj.component.length > 0) mixRatioMap[tindex] = std_glj.component
  519. let tdata = ration_glj_facade.getGLJSearchInfo(newGLJ);
  520. gljKeyMap[tindex] = tdata;
  521. gljCodes.push(tdata.code);
  522. newRationGLJList.push(newGLJ);
  523. }
  524. }
  525. [newRationGLJList, projectGLJList] = await getProjectGLJinfo(newRation.projectID,newRationGLJList,gljKeyMap,gljCodes,mixRatioMap,unitPriceFileId,ext);
  526. let InfoFromProjectGLJ = +new Date();
  527. console.log("找到项目工料机时间-------------------------------"+(InfoFromProjectGLJ - stdGLJMapTime));
  528. }
  529. if(isMaterial == true) return [newRationGLJList,projectGLJList];//如果是材料计算的工料机,这里返回就可以了
  530. if(newRationGLJList.length>0){
  531. await ration_glj.insertMany(newRationGLJList);
  532. }
  533. let after = +new Date();
  534. console.log("总操作时间为-------------------------------"+(after-first));
  535. return [newRationGLJList,projectGLJList];
  536. }
  537. async function getProjectGLJinfo(projectID,t_newRationGLJList,gljKeyMap,gljCodes,mixRatioMap,unitPriceFileId,ext){//批量插入或查找项目工料机信息
  538. //先根据工料机编号在项目工料机中查找工料机是否存在
  539. let projectGLJMap={};
  540. let projectGLJList = [];
  541. let newProjectGLJList=[];//工料机ID要重新去取
  542. let connectKeyList = [];
  543. let CCSMap = {keyMap:{},codes:[]};//需要添加车船税的机械台班
  544. let newRationGLJList=[];
  545. let gljListModel = new GLJListModel();
  546. let t_projectGLJList = await projectGLJModel.find({'project_id':projectID,'code':{'$in':gljCodes}}).lean();
  547. for(let pg of t_projectGLJList){
  548. let pindex = getIndex(pg);
  549. projectGLJMap[pindex] = pg;
  550. }
  551. for(let key in gljKeyMap){
  552. if(!projectGLJMap[key]){//如果项目工料机不存在,则添加
  553. newProjectGLJList.push(gljKeyMap[key]);
  554. projectGLJMap[key] = gljKeyMap[key];
  555. if(gljKeyMap[key].type == 301){//如果是机械台班,需看看有没有车船税
  556. CCSMap.keyMap[key] = true;
  557. CCSMap.codes.push(gljKeyMap[key].code);
  558. }
  559. }
  560. //查看组成物
  561. if(gljListModel.ownCompositionTypes.indexOf(gljKeyMap[key].type)!=-1){//有组成物的类型
  562. connectKeyList.push(key);
  563. }
  564. }
  565. let [existMixRatioMap,mixRatioInsertData,missCodeList] = await getMixRatioInfo(projectID,projectGLJMap,newProjectGLJList,mixRatioMap,connectKeyList,unitPriceFileId,CCSMap,ext);
  566. if(missCodeList.length > 0) gljCodes = gljCodes.concat(missCodeList);
  567. //处理车般税相关,车船税是添加项目时,项目工料机,和单价文件里自动添加的 --- todo
  568. let [unitPriceMap,newUnitPriceList] = await getUnitPriceData(newProjectGLJList,gljCodes,unitPriceFileId);
  569. if(mixRatioInsertData.length > 0) await mixRatioModel.insertMany(mixRatioInsertData);
  570. //插入项目工料机
  571. if(newProjectGLJList.length > 0){
  572. await setIDfromCounter("glj_list",newProjectGLJList);
  573. await projectGLJModel.insertMany(newProjectGLJList);
  574. }
  575. //组装数据
  576. for(let ration_glj of t_newRationGLJList){
  577. let rkey = getIndex(ration_glj);
  578. let pglj = projectGLJMap[rkey];
  579. let subList = [];
  580. setUnitPrice(pglj,unitPriceMap);
  581. if(existMixRatioMap[rkey]){//如果有组成物
  582. for(let m of existMixRatioMap[rkey]){
  583. let mpglj = projectGLJMap[getIndex(m)]
  584. if(mpglj){
  585. let cglj = _.clone(mpglj);
  586. setUnitPrice(cglj,unitPriceMap);
  587. cglj.ratio_data = m;
  588. subList.push(cglj);
  589. }else{
  590. throw `组成物${m.name}对应的项目工料机没有找到`;
  591. }
  592. }
  593. pglj.subList =subList;
  594. }
  595. ration_glj.projectGLJID = pglj.id;
  596. newRationGLJList.push(ration_glj_facade.createNewRecord(ration_glj));
  597. projectGLJList.push(pglj);
  598. }
  599. return [newRationGLJList, projectGLJList];
  600. function setUnitPrice(p,unitPriceMap){
  601. p.unit_price = unitPriceMap[getIndex(p)];
  602. }
  603. }
  604. //找到并返回单价文件信息,如果没有自动插入
  605. async function getUnitPriceData(newProjectGLJList,gljCodes,unitPriceFileId){
  606. let unitPriceMap = {};
  607. let newUnitPriceList = [];
  608. let unitPriceList = await unitPriceModel.find({unit_price_file_id: unitPriceFileId,'code':{'$in':gljCodes}}).lean();
  609. for(let u of unitPriceList){
  610. unitPriceMap[getIndex(u)]=u;
  611. }
  612. for(let np of newProjectGLJList){
  613. let pkey = getIndex(np);
  614. if(unitPriceMap[pkey]) continue;
  615. let insertData = {
  616. code: np.code,
  617. base_price: np.base_price,
  618. market_price: np.market_price,
  619. unit_price_file_id: unitPriceFileId,
  620. name: np.name,
  621. specs:np.specs?np.specs:'',
  622. original_code:np.original_code,
  623. unit:np.unit?np.unit:'',
  624. type: np.type,
  625. short_name: np.shortName !== undefined ? np.shortName : '',
  626. glj_id: np.glj_id,
  627. is_add:0,
  628. grossWeightCoe:np.grossWeightCoe,
  629. purchaseStorageRate:np.purchaseStorageRate,
  630. offSiteTransportLossRate:np.offSiteTransportLossRate,
  631. handlingLossRate:np.handlingLossRate
  632. };
  633. if(np.from=='cpt') insertData.is_add=1;//如果是来自补充工料机,则都添加新增标记
  634. if(insertData.code != insertData.original_code) insertData.is_add=1;//添加的时候如果是复制整块来的,可能在源项目中是新增的工料机,这里也要添上(暂时可能还用不到)
  635. newUnitPriceList.push(insertData);
  636. unitPriceMap[pkey] = insertData;
  637. }
  638. if(newUnitPriceList.length > 0){
  639. await setIDfromCounter("unit_price",newUnitPriceList);
  640. await unitPriceModel.insertMany(newUnitPriceList);
  641. }
  642. return [unitPriceMap,newUnitPriceList];
  643. }
  644. async function getMixRatioInfo(projectID,projectGLJMap,newProjectGLJList,mixRatioMap,connectKeyList,unitPriceFileId,CCSMap,ext){//取组成物信息,得到缺少的组成物情况
  645. let missCodeList = []; //所有组成物信息的编码,用来统一查询对应的项目工料机是否存在
  646. let existMixRatioMap ={};
  647. let codeMap={};//用来去重
  648. let mixRatioInsertData = [];
  649. // 1. 先检查现在的组成物表中,是否有相关信息 - 生成映射记录
  650. if(connectKeyList.length > 0){//有组成物的话从数据库中取出组成物信息
  651. let mixRatioList = await mixRatioModel.find({'unit_price_file_id': unitPriceFileId,'connect_key': {'$in':connectKeyList}}).lean();
  652. for(let m of mixRatioList){
  653. //组成物信息分组,查看哪些是已经存在的
  654. existMixRatioMap[m.connect_key]?existMixRatioMap[m.connect_key].push(m):existMixRatioMap[m.connect_key]=[m];
  655. //查看组成物对应的项目工料机是否存在,如果不存在,要插入项目工料机
  656. let mkey = getIndex(m);
  657. if(!projectGLJMap[mkey] && !codeMap[m.code]){//如果之前查出来的项目工料机中不包含组成物的信息,要加到missCode里面再查找一次项目工料机看是否存在
  658. missCodeList.push(m.code);
  659. codeMap[m.code] = true;
  660. }
  661. }
  662. // 2 将第一步得到的映射表 与在标准库查询父工料机得到的映射表对比,得出哪些组物成还需要添加,获得库ID
  663. let stdIDs = [];
  664. let comIDs = [];
  665. let missMixRatioGroup = [];
  666. for(let ck of connectKeyList){//查看项目中组成物信息是否已经存在,如果不存在,则用插定额时获取的组成物信息从数据库中获取
  667. if(!existMixRatioMap[ck] && mixRatioMap[ck] && mixRatioMap[ck].length > 0){//组成物信息不存在
  668. let pglj = projectGLJMap[ck];//取出父数据
  669. let from = pglj.from === undefined|| pglj.from ===null || pglj.from === ""?'std' : pglj.from;
  670. for(let c of mixRatioMap[ck]){
  671. if(from == "std"){//标准的工料机只来自标准的
  672. stdIDs.push(c.ID);
  673. }else{
  674. c.isStd?stdIDs.push(c.ID):comIDs.push(c.ID);
  675. }
  676. }
  677. missMixRatioGroup.push({'connect_key':ck,'list':mixRatioMap[ck],'from':from});
  678. }
  679. }
  680. //3.统一查询所有组成物在标准库中的详细信息
  681. let stdMixMap = {};
  682. //整理需插入的组成物列表的数据
  683. //来自标准工料机
  684. if(stdIDs.length > 0){
  685. stdIDs = _.uniq(stdIDs);//去重
  686. let stdMixList = await std_glj_lib_gljList_model.find({'ID':{'$in':stdIDs}}).lean();
  687. for(let sm of stdMixList){
  688. stdMixMap[sm.ID] = sm;
  689. let skey = getIndex(sm,['code','name','specs','unit','gljType']);
  690. if(!projectGLJMap[skey] && !codeMap[sm.code]){
  691. missCodeList.push(sm.code);
  692. codeMap[sm.code] = true;
  693. }
  694. }
  695. }
  696. //来自组成物工料机
  697. let comMixMap = {};
  698. if(comIDs.length > 0){
  699. comIDs = _.uniq(comIDs);//去重
  700. let comMixList = await complementaryGljLibModel.find({'ID':{'$in':comIDs}}).lean();
  701. for(let cm of comMixList){
  702. comMixMap[cm.ID] = cm;
  703. let ckey = getIndex(cm,['code','name','specs','unit','gljType']);
  704. if(!projectGLJMap[ckey] && codeMap[cm.code]){
  705. missCodeList.push(cm.code);
  706. codeMap[cm.code] = true;
  707. }
  708. }
  709. }
  710. //4.生成需要插入组成物表的数据
  711. for(let mg of missMixRatioGroup){//整理需要插入组成物列表的数据
  712. for(let tc of mg.list){
  713. let consumpiton = tc.consumeAmt;
  714. //只有标准的工料机的组成物才会有多单价、多组成物消耗量的情况
  715. if(mg.from == 'std' && ext && ext.quantityField &&( tc.consumeAmtProperty[ext.quantityField]!= undefined && tc.consumeAmtProperty[ext.quantityField]!=null)){
  716. consumpiton = tc.consumeAmtProperty[ext.quantityField];
  717. }
  718. let mfrom = mg.from == 'std' || tc.isStd?'std':'cpt';
  719. let tmp = mfrom == 'std'?stdMixMap[tc.ID]:comMixMap[tc.ID];//取出之前库中查到的工料机
  720. let mixRatioData = {
  721. consumption: consumpiton,
  722. glj_id: tmp.ID,
  723. unit_price_file_id: unitPriceFileId,
  724. connect_key: mg.connect_key,
  725. type: tmp.gljType,
  726. code: tmp.code,
  727. specs:tmp.specs?tmp.specs:"",
  728. name:tmp.name,
  729. unit:tmp.unit?tmp.unit:'',
  730. from:mfrom
  731. };
  732. mixRatioInsertData.push(mixRatioData);
  733. }
  734. }
  735. //4.5 处理车船税问题,查询机械台班是否需要添加车船税
  736. if(CCSMap.codes.length > 0){
  737. let unitFileInfo = await unitPriceFileModel.findOne({id:unitPriceFileId}).lean();
  738. if(unitFileInfo.vvTaxFileID && unitFileInfo.vvTaxFileID!=""){
  739. let needCCS = false;
  740. let items = await vvTaxModel.find({libID:unitFileInfo.vvTaxFileID,'code':{'$in':CCSMap.codes}}).lean();
  741. for(let i of items){
  742. let ikey = getIndex(i);
  743. if(CCSMap.keyMap[ikey]){
  744. needCCS = true;
  745. mixRatioInsertData.push(gljUtil.getBaseCCSMixRatio(unitPriceFileId,i.vehicleVesselTax,ikey))
  746. }
  747. }
  748. if(needCCS && !codeMap["80CCS"]) missCodeList.push("80CCS");
  749. }
  750. }
  751. if(mixRatioInsertData.length > 0) await setIDfromCounter("mix_ratio",mixRatioInsertData,existMixRatioMap,'connect_key');
  752. //await mixRatioModel.insertMany(mixRatioInsertData); 因为没有事务添加组成物数据要放在添加单价文件数据之后
  753. //5.查询组成物对应的项目工料机是否存在,如果不存在,生成项目工料机信息
  754. let projectGLJList = await projectGLJModel.find({'project_id':projectID,'code':{'$in':missCodeList}}).lean();
  755. for(let pg of projectGLJList){
  756. let pindex = getIndex(pg);
  757. projectGLJMap[pindex] = pg;
  758. }
  759. let lessMix = [];//组成物表存在,项目工料机不存在的数据
  760. let lessMixMap = {};//防止重复添加
  761. for(let connect_key in existMixRatioMap){
  762. let mixRatios = existMixRatioMap[connect_key];
  763. for(let m of mixRatios){
  764. let mk = getIndex(m);
  765. if(!projectGLJMap[mk] && !lessMixMap[mk]){//如果组成物对应的项目工料机不存在
  766. let nglj = null;
  767. if(m.from == 'std'){//这里有值,说明是刚添加到组成物文件中的数据
  768. nglj = stdMixMap[m.glj_id];
  769. }else if(m.from == 'cpt'){//这里有值,说明是刚添加到组成物文件中的数据
  770. nglj = comMixMap[m.glj_id];
  771. }
  772. if(nglj){
  773. nglj.from = m.from;
  774. let np = getProjectGLJNewData(nglj,projectID,ext);
  775. newProjectGLJList.push(np);
  776. projectGLJMap[mk] = np;
  777. }else{//这里没找到,说明是组成物文件里有,但是项目工料机没有的数据
  778. lessMix.push(m);
  779. }
  780. lessMixMap[mk] = true;//只要处理过一次,就不用再重新处理了,机械组成物,比如柴油这些,会出现多次
  781. }
  782. }
  783. }
  784. //6. 组成物文件里有,但是项目工料机没有的数据(共用单价文件等情况产生)
  785. let lessIDList=[];
  786. let uniqMap ={};//去重
  787. let lessStdMix = [];//防止组成物中改了名称等,但是通过glj_id取出来的是还没改前的原始数据
  788. if(lessMix.length > 0){
  789. for(let lm of lessMix){
  790. let parentglj = projectGLJMap[lm.connect_key];
  791. if(!parentglj) throw `含有组成物工料机${lm.connect_key},没有找到,添加定额失败`;
  792. if((parentglj.from == "std" || lm.from == "std") && lm.code!="80CCS"){//车船税特殊处理
  793. if(!uniqMap[lm.glj_id]){
  794. lessIDList.push(lm.glj_id);
  795. uniqMap[lm.glj_id] = lm;
  796. }
  797. lessStdMix.push(lm);
  798. }else {//来自组成物的直接设置
  799. lm.from = 'cpt';
  800. lm.gljType = lm.type;
  801. let t_mg = getProjectGLJNewData(lm,projectID);
  802. newProjectGLJList.push(t_mg);
  803. projectGLJMap[getIndex(lm)] = t_mg;
  804. }
  805. }
  806. }
  807. if(lessIDList.length > 0){
  808. let less_stds = await std_glj_lib_gljList_model.find({'ID':{'$in':lessIDList}}).lean();
  809. let less_stds_map = {};
  810. for(let les of less_stds){
  811. less_stds_map[les.ID] = les;
  812. }
  813. for(let t_l_m of lessStdMix){
  814. let t_nglj = less_stds_map[t_l_m.glj_id];
  815. t_nglj.from = 'std';
  816. //防止组成物中改了名称等,但是通过glj_id取出来的是还没改前的原始数据
  817. t_nglj.name = t_l_m.name;
  818. t_nglj.code = t_l_m.code;
  819. t_nglj.gljType = t_l_m.type;
  820. t_nglj.specs = t_l_m.specs;
  821. t_nglj.unit = t_l_m.unit;
  822. let t_np = getProjectGLJNewData(t_nglj,projectID,ext);
  823. newProjectGLJList.push(t_np);
  824. projectGLJMap[getIndex(t_l_m)] = t_np;
  825. }
  826. }
  827. }
  828. return [existMixRatioMap,mixRatioInsertData,missCodeList]
  829. }
  830. //根据缺少项目工料机的组成物信息,反向生成对应的项目工料机
  831. async function getNewProjectGLJFromMissMixratio(projectID,lessMix,projectGLJMap,newProjectGLJList,ext){
  832. let lessIDList=[];
  833. let uniqMap ={};//去重
  834. let lessStdMix = [];//防止组成物中改了名称等,但是通过glj_id取出来的是还没改前的原始数据
  835. if(lessMix.length > 0){
  836. for(let lm of lessMix){
  837. let parentglj = projectGLJMap[lm.connect_key];
  838. if(!parentglj) throw `含有组成物工料机${lm.connect_key},没有找到,添加定额失败`;
  839. if((parentglj.from == "std" || lm.from == "std") && lm.code!="80CCS"){//车船税特殊处理
  840. if(!uniqMap[lm.glj_id]){
  841. lessIDList.push(lm.glj_id);
  842. uniqMap[lm.glj_id] = lm;
  843. }
  844. lessStdMix.push(lm);
  845. }else {//来自组成物的直接设置
  846. lm.from = 'cpt';
  847. lm.gljType = lm.type;
  848. let t_mg = getProjectGLJNewData(lm,projectID);
  849. newProjectGLJList.push(t_mg);
  850. projectGLJMap[getIndex(lm)] = t_mg;
  851. }
  852. }
  853. }
  854. if(lessIDList.length > 0){
  855. let less_stds = await std_glj_lib_gljList_model.find({'ID':{'$in':lessIDList}}).lean();
  856. let less_stds_map = {};
  857. for(let les of less_stds){
  858. less_stds_map[les.ID] = les;
  859. }
  860. for(let t_l_m of lessStdMix){
  861. let t_nglj = less_stds_map[t_l_m.glj_id];
  862. t_nglj.from = 'std';
  863. //防止组成物中改了名称等,但是通过glj_id取出来的是还没改前的原始数据
  864. t_nglj.name = t_l_m.name;
  865. t_nglj.code = t_l_m.code;
  866. t_nglj.gljType = t_l_m.type;
  867. t_nglj.specs = t_l_m.specs;
  868. t_nglj.unit = t_l_m.unit;
  869. let t_np = getProjectGLJNewData(t_nglj,projectID,ext);
  870. newProjectGLJList.push(t_np);
  871. projectGLJMap[getIndex(t_l_m)] = t_np;
  872. }
  873. }
  874. return newProjectGLJList;
  875. }
  876. function getProjectGLJNewData(tmp,projectId,ext){
  877. let gljData = {
  878. glj_id: tmp.ID,
  879. repositoryId:tmp.repositoryId,
  880. project_id: projectId,
  881. code: tmp.code,
  882. name: tmp.name,
  883. specs: tmp.specs?tmp.specs:'',
  884. unit: tmp.unit === undefined ? '' : tmp.unit,
  885. type: tmp.gljType,
  886. adjCoe:tmp.adjCoe,
  887. original_code:tmp.code,
  888. materialType: tmp.materialType, //三材类别
  889. materialCoe: tmp.materialCoe,
  890. base_price: tmp.basePrice,
  891. market_price: tmp.basePrice,
  892. from:tmp.from?tmp.from:"std"
  893. };
  894. if(gljData.from == 'std' && ext && ext.priceField &&(tmp.priceProperty && tmp.priceProperty[ext.priceField]!= undefined && tmp.priceProperty[ext.priceField]!=null)){
  895. const basePrice = scMathUtil.roundTo(tmp.priceProperty[ext.priceField],-6);
  896. gljData.base_price = basePrice;
  897. gljData.market_price = basePrice;
  898. }
  899. return gljData;
  900. }
  901. async function setIDfromCounter(name,list,map,keyfield){//map,keyfield
  902. let update = {$inc: {sequence_value: list.length}};
  903. let condition = {_id: name};
  904. let options = {new: true};
  905. // 先查找更新
  906. let counter = await counterModel.findOneAndUpdate(condition, update, options);
  907. let firstID = counter.sequence_value - (list.length - 1);
  908. for(let a of list){
  909. a.id = firstID;
  910. firstID+=1
  911. if(map && keyfield){
  912. let key = a[keyfield];
  913. map[key]?map[key].push(a):map[key]=[a]
  914. }
  915. }
  916. }
  917. function getStdGlj(sub,stdGLJMap,cptGLJMap,newGLJ,ext) {
  918. let std_glj = null;
  919. if(sub.type == 'complementary'){//有可能来自标准工料机库或补充工料机库
  920. std_glj = cptGLJMap[sub.gljId];
  921. newGLJ.from = 'cpt';
  922. }else {
  923. std_glj = stdGLJMap[sub.gljId];
  924. newGLJ.from = 'std';
  925. //多单价情况处理
  926. if(ext && ext.priceField && std_glj && std_glj.priceProperty){
  927. std_glj.basePrice = std_glj.priceProperty[ext.priceField];
  928. }
  929. }
  930. return std_glj;
  931. }
  932. async function deleRationSubRecode(projectID,rationID,cleanzmhs=false) {//删除挂在定额下的数据,如工程量明细,定额工料机等
  933. let delete_query={projectID: projectID, rationID: rationID};
  934. //删除工程量明细
  935. await deleteSubListByQuery(delete_query,cleanzmhs) ;
  936. }
  937. async function deleteSubListByQuery(delete_query,cleanzmhs=false) {
  938. if(cleanzmhs == false){//清空子目换算即cleanzmh==true时不需要清空工程量明细、模板关联子目、安装增加费
  939. await quantity_detail.deleteByQuery(delete_query) ;//删除工程量明细
  940. await rationInstallationModel.deleteMany(delete_query);//删除安装增加费
  941. await rationTemplateModel.deleteMany(delete_query);//删除模板关联子目
  942. }
  943. //to do稳定土也要删除
  944. await ration_coe.deleteMany(delete_query);//删除附注条件
  945. await ration_glj.deleteMany(delete_query);//删除定额工料机
  946. }
  947. async function updateCoeAdjust(data,compilation) {
  948. let replace = [],projectGLJList=[];
  949. await ration_coe.update({ID:data.ID},data.doc);
  950. //添加单个工料机的情况
  951. if (data.add.length > 0){
  952. let [tg,pl] = await ration_glj_facade.insertAddTypeGLJ(data.add,compilation);
  953. if(pl.length > 0) projectGLJList = projectGLJList.concat(pl);
  954. }
  955. if(data.delete.length > 0) await ration_glj_facade.deleteGLJ(data.delete);
  956. //替换工料机的情况
  957. if (data.replace.length > 0){
  958. for(let r of data.replace){
  959. let r_result = await ration_glj_facade.replaceGLJByData(r,compilation);
  960. replace.push(r_result.data) ;
  961. projectGLJList.push(r_result.projectGLJ);
  962. if(r_result.newRecodes.length > 0) data.add = data.add.concat(r_result.newRecodes);
  963. if(r_result.deleteList.length > 0) data.delete = data.delete.concat(r_result.deleteList);
  964. }
  965. }
  966. let cal_result = await glj_calculate_facade.calculateQuantity({projectID:data.projectID,rationID:data.rationID},null,true);
  967. let coe = {
  968. query:{ID:data.ID,projectID:data.projectID},
  969. doc:data.doc
  970. };
  971. let ration_glj ={
  972. quantityRefresh:true,
  973. glj_result:cal_result.glj_result
  974. };
  975. let ration = {
  976. ID:cal_result.rationID,
  977. adjustState:cal_result.adjustState,
  978. name:cal_result.rationName
  979. };
  980. return {coe:coe,ration_glj:ration_glj,ration:ration,add:data.add,delete:data.delete,replace:replace,projectGLJList:projectGLJList}
  981. }
  982. async function updateRation(std,defaultLibID,rationID,billsItemID,projectID,calQuantity,cleanzmh=false) {
  983. // insertNewRation
  984. let ration ={};
  985. ration.code = std.code;
  986. ration.name = std.name;
  987. ration.caption = std.caption;
  988. ration.unit = std.unit;
  989. if (std.type === 'std') {
  990. ration.libID = std.rationRepId;
  991. ration.stdID = std.ID;
  992. }
  993. ration.content = std.jobContent;
  994. ration.adjustState = '';
  995. ration.isFromDetail=0;
  996. ration.isSubcontract=false;
  997. ration.fees=[];
  998. if (std.chapter) {
  999. ration.comments = std.chapter.explanation;
  1000. ration.ruleText = std.chapter.ruleText;
  1001. }
  1002. ration.from = std.type === 'complementary' ? 'cpt' : 'std';
  1003. //定额前缀 none:0, complementary:1, borrow: 2
  1004. ration.prefix = '';
  1005. //借用优先级比补充高
  1006. if(std.rationRepId !== parseInt(defaultLibID)){//借用
  1007. ration.prefix = '借';
  1008. }
  1009. else if(std.rationRepId === defaultLibID && ration.from === 'cpt') {
  1010. ration.prefix = '补';
  1011. }
  1012. ration.rationAssList =await createRationAss(std);//生成辅助定额
  1013. if(cleanzmh==false){//如果是清空子目换算,即cleanzmh==true 保留定额工程量、工程量表达式、含量(分解系数)、取费专业(取费类别)
  1014. if(std.feeType == undefined || std.feeType == null || std.feeType ==''){//定额取费专业为空的情况下,取项目属性中的定额取费专业ID
  1015. ration.programID = await getProgramForProject(projectID);
  1016. }else {
  1017. ration.programID = std.feeType;
  1018. }
  1019. if( calQuantity){
  1020. await CalculateQuantity(ration,billsItemID,projectID);
  1021. }
  1022. }
  1023. let unsetObject = {
  1024. "marketUnitFee":1,
  1025. 'marketTotalFee':1,
  1026. "maskName":1
  1027. }
  1028. let newRation = await ration_model.model.findOneAndUpdate({ID:rationID,projectID:projectID},{"$set":ration,"$unset":unsetObject},{new: true});//;
  1029. return newRation;
  1030. }
  1031. async function setEmptyRation(projectID,rationID){
  1032. let ration ={};
  1033. ration.code = "";
  1034. ration.name = "";
  1035. ration.caption = "";
  1036. ration.unit = "";
  1037. ration.libID = null;
  1038. ration.content = "";
  1039. ration.adjustState = '';
  1040. ration.isFromDetail=0;
  1041. ration.isSubcontract=false;
  1042. ration.fees=[];
  1043. ration.comments = "";
  1044. ration.ruleText = "";
  1045. ration.quantity="";
  1046. ration.contain="";
  1047. ration.quantityEXP="";
  1048. ration.from = 'std';
  1049. //定额前缀 none:0, complementary:1, borrow: 2
  1050. ration.prefix = '';
  1051. ration.rationAssList = [];
  1052. ration.marketUnitFee ="";
  1053. ration.marketTotalFee ="";
  1054. ration.maskName = "";
  1055. ration.targetTotalFee ='';
  1056. ration.targetUnitFee = "";
  1057. ration.deleteInfo = null;
  1058. ration.quantityCoe = {};
  1059. ration.rationQuantityCoe="";
  1060. ration.tenderQuantity = "";
  1061. ration.programID = null;
  1062. let newRation = await ration_model.model.findOneAndUpdate({ID:rationID,projectID:projectID},{"$set":ration},{new: true});//;
  1063. return {ration:newRation,ration_gljs:[],ration_coes:[],ration_installs:[]};
  1064. }
  1065. async function createRationAss(std,isMaterial) {
  1066. let rationAssList = [];//生成辅助定额
  1067. if(std.hasOwnProperty('rationAssList')&&std.rationAssList.length>0){
  1068. let assGroup = _.groupBy(std.rationAssList,'name');
  1069. for(let key in assGroup){
  1070. let assList = assGroup[key];
  1071. let ass = assList[0];
  1072. ass._doc.actualValue = ass.stdValue;
  1073. ass._doc.isAdjust = 0;
  1074. if(_.isString(ass._doc.assistCode)) ass._doc.assistCode = ass._doc.assistCode.replace("\n","");
  1075. if(_.isString(ass._doc.thirdRationCode)) ass._doc.thirdRationCode = ass._doc.thirdRationCode.replace("\n","");
  1076. if(assList.length > 1){
  1077. ass._doc.groupList = JSON.parse(JSON.stringify(assList)) ;
  1078. ass._doc.maxValue = assList[assList.length-1]._doc.maxValue;
  1079. }
  1080. if(isMaterial == true){//材料计算进来的,直接保存辅助定额的信息 //常规的定额以后可以考虑也这样做
  1081. let t_assRation = await rationItemModel.findOne({rationRepId:std.rationRepId,code:ass.assistCode}).lean();
  1082. if(t_assRation) ass._doc.assRation = t_assRation;
  1083. }
  1084. rationAssList.push(ass);
  1085. }
  1086. }
  1087. return rationAssList;
  1088. }
  1089. async function CalculateQuantity (ration,billsItemID,projectID) {
  1090. // calculate ration Quantity
  1091. let project = await projectModel.findOne({ID:projectID});
  1092. let decimalObject =await decimal_facade.getProjectDecimal(projectID,project);
  1093. let quantity_decimal = (decimalObject&&decimalObject.ration&&decimalObject.ration.quantity)?decimalObject.ration.quantity:3;
  1094. let pbill = await bill_model.model.findOne({projectID:projectID,ID:billsItemID});
  1095. let rationTimes = 1 ;//清单单位转定额单位的倍数,如 kg 转 t 时是1000
  1096. let t_unit = ration.unit?ration.unit:"";
  1097. let b_unit = pbill.unit?pbill.unit:"";
  1098. ration.quantityEXP="QDL";
  1099. if((/.*kg$/i).test(b_unit)){
  1100. if((/t/i).test(t_unit)) {
  1101. rationTimes = 1000;//如 kg 转 t 时是1000
  1102. ration.quantityEXP="QDL*0.001"
  1103. }
  1104. if((/10t/i).test(t_unit)){
  1105. rationTimes = 10000;//如 kg 转 10t 时是1000
  1106. ration.quantityEXP="QDL*0.0001"
  1107. }
  1108. }
  1109. /* let t_unit = ration.unit?ration.unit.replace(/^\d+/,""):""; 2019-02-01 养护去掉清单与定额单位的这个判断
  1110. if(t_unit!=pbill.unit){//如果定额工程量的单位去除前面的数字后不等于清单单位,定额工程量保持不变
  1111. return ;
  1112. }*/
  1113. let billsQuantity = pbill.quantity ? pbill.quantity : 0;
  1114. let bill_decimal = await decimal_facade.getBillsQuantityDecimal(projectID,pbill.unit,project);
  1115. let ftimes = rationTimes == 1?FilterNumberFromUnit(ration.unit):rationTimes;
  1116. billsQuantity=scMathUtil.roundForObj(billsQuantity,bill_decimal);
  1117. ration.quantity = scMathUtil.roundForObj(billsQuantity / ftimes ,quantity_decimal);//不管是否打勾都做转换
  1118. ration.contain = scMathUtil.roundForObj(ration.quantity/billsQuantity,6);
  1119. };
  1120. async function getProgramForProject(projectID){
  1121. let project = await projectModel.findOne({ID:projectID});
  1122. return project.property.engineering;
  1123. }
  1124. function FilterNumberFromUnit (unit) {
  1125. let reg = new RegExp('^[0-9]+');
  1126. if (reg.test(unit)) {
  1127. return parseInt(unit.match(reg)[0]);
  1128. } else {
  1129. return 1;
  1130. }
  1131. };
  1132. function getIndex(obj,tpops){
  1133. let pops = tpops?tpops:['code','name','specs','unit','type'];
  1134. let t_index = '';
  1135. let k_arr=[];
  1136. for(let p of pops){
  1137. let tmpK = (obj[p]==undefined||obj[p]==null||obj[p]=='')?'null':obj[p];
  1138. k_arr.push(tmpK);
  1139. }
  1140. t_index=k_arr.join("|-|");
  1141. return t_index;
  1142. }