ration_facade.js 53 KB

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