quantity_detail_facade.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /**
  2. * Created by chen on 2017/7/20.
  3. */
  4. /**
  5. * Created by chen on 2017/7/10.
  6. */
  7. let mongoose = require('mongoose');
  8. let consts = require('../../main/models/project_consts');
  9. let commonConsts = consts.commonConst;
  10. let _=require("lodash");
  11. let async_n = require("async");
  12. let quantity_detail_model = mongoose.model('quantity_detail');
  13. const uuidV1 = require('uuid/v1');
  14. let ration_model = mongoose.model('ration');
  15. let bill_model=mongoose.model("bills");
  16. const scMathUtil = require('../../../public/scMathUtil').getUtil();
  17. let decimal_facade = require('./decimal_facade');
  18. module.exports={
  19. save:save,
  20. getData:getData,
  21. deleteByRation:deleteByRation,
  22. deleteByBill:deleteByBill,
  23. quantityEditChecking:quantityEditChecking,
  24. saveQuantityDetail:saveQuantityDetail,
  25. update:update,
  26. updateRegex:updateRegex,
  27. insertRecode:insertRecode,
  28. deleteRecode:deleteRecode,
  29. swapRow:swapRow,
  30. deleteByQuery:deleteByQuery
  31. };
  32. let operationMap={
  33. 'ut_update':update_quantity_detail,
  34. };
  35. let updateFunctionMap = {
  36. 'insertRecode':insertRecode
  37. }
  38. async function saveQuantityDetail(datas) {
  39. let doc = datas;
  40. doc.ID = uuidV1();
  41. if(doc.refreshQuantity==false){ //如果选择了不替换工程量,则清空
  42. await cleanQuantityDetail(doc);
  43. return {};
  44. }
  45. if(doc.hasOwnProperty('regex')){
  46. return await insertRecodeWithReg(doc);
  47. }else {
  48. return await createNormalRecode(doc);
  49. }
  50. }
  51. async function update(datas) {
  52. let doc = datas.doc;
  53. if(doc.hasOwnProperty('isSummation')){
  54. return await doIsSummationUpdate(datas.query,doc);
  55. }else {
  56. await quantity_detail_model.update(datas.query,doc);
  57. return datas;
  58. }
  59. }
  60. async function swapRow(datas) {
  61. for(let task of datas){
  62. await update(task);
  63. }
  64. return {refreshList:datas};
  65. }
  66. async function updateRegex(datas) {
  67. let resultObjec ={};
  68. let detailList = [];
  69. let node ={};
  70. let decimal =await decimal_facade.getProjectDecimal(datas.query.projectID);
  71. if(datas.query.hasOwnProperty('rationID')){
  72. detailList = await quantity_detail_model.find({'projectID':datas.query.projectID,'rationID':datas.query.rationID}).sort('seq').exec();
  73. node.type = consts.projectConst.RATION;
  74. node.ID = datas.query.rationID;
  75. }else {
  76. detailList = await quantity_detail_model.find({'projectID':datas.query.projectID,'billID':datas.query.billID}).sort('seq').exec();
  77. node.type = consts.projectConst.BILLS;
  78. node.ID=datas.query.billID;
  79. }
  80. let regex;
  81. let result;
  82. if(datas.doc.regex==null){
  83. result=0;
  84. datas.doc.referenceIndexs=[];
  85. }else{
  86. if(datas.doc.hasOwnProperty('result')){//如果前端已经计算好了
  87. result = datas.doc.result;
  88. }else {
  89. regex = datas.doc.regex.toUpperCase();
  90. let referenceIndexs = datas.doc.referenceIndexs;
  91. result = getEvalResult(referenceIndexs,detailList,regex,decimal);
  92. }
  93. }
  94. detailList[datas.query.index].result =result;
  95. detailList[datas.query.index].regex=datas.doc.regex;
  96. detailList[datas.query.index].referenceIndexs =datas.doc.referenceIndexs;
  97. let updateTasks =[];
  98. datas.doc.result=result;
  99. updateTasks.push({
  100. query:{
  101. ID:datas.query.ID,
  102. projectID:datas.query.projectID
  103. },
  104. doc:datas.doc
  105. })
  106. updateReferenceRecode(datas.query.index+1,detailList,updateTasks);
  107. await quantity_detail_model.bulkWrite(generateUpdateTaks(updateTasks));
  108. resultObjec.refreshList=updateTasks;
  109. if(datas.query.refreshQuantity==true){
  110. let data = await summateResults(datas.query,detailList,decimal);
  111. node.data = data;
  112. resultObjec.node = node;
  113. }
  114. return resultObjec;
  115. }
  116. async function cleanQuantityDetail(doc) {
  117. let query = {
  118. projectID:doc.projectID
  119. }
  120. if(doc.hasOwnProperty('rationID')){
  121. query.rationID = doc.rationID;
  122. }else {
  123. query.billID = doc.billID;
  124. }
  125. return await quantity_detail_model.deleteMany(query);
  126. }
  127. async function insertRecode(doc){
  128. let query = {
  129. projectID:doc.projectID,
  130. seq : { $gte: doc.seq }
  131. }
  132. if(doc.hasOwnProperty('rationID')){
  133. query.rationID = doc.rationID;
  134. }else {
  135. query.billID = doc.billID;
  136. }
  137. let quantity_detail_List = await getDatailList(doc,{data:{}});
  138. let update_task = getUpdateReferenceTask(quantity_detail_List,doc.seq,1);
  139. await quantity_detail_model.update(query,{$inc:{seq:1}},{multi: true});
  140. if(update_task.length>0){
  141. await quantity_detail_model.bulkWrite(generateUpdateTaks(update_task));
  142. }
  143. doc.ID = uuidV1();
  144. let newrecode = await quantity_detail_model.create(doc);
  145. let data={
  146. doc:newrecode,
  147. resort:true,
  148. update_task:update_task
  149. }
  150. return data;
  151. }
  152. async function doInsertRecode(doc) {
  153. let result={
  154. err:null
  155. }
  156. try{
  157. let query = {
  158. projectID:doc.projectID,
  159. seq : { $gte: doc.seq }
  160. }
  161. if(doc.hasOwnProperty('rationID')){
  162. query.rationID = doc.rationID;
  163. }else {
  164. query.billID = doc.billID;
  165. }
  166. let quantity_detail_List = await getDatailList(doc,{data:{}});
  167. let update_task = getUpdateReferenceTask(quantity_detail_List,doc.seq,1);
  168. await quantity_detail_model.update(query,{$inc:{seq:1}},{multi: true});
  169. if(update_task.length>0){
  170. await quantity_detail_model.bulkWrite(generateUpdateTaks(update_task));
  171. }
  172. let newrecode = await quantity_detail_model.create(doc);
  173. let returndata ={
  174. updateTpye:commonConsts.UT_CREATE,
  175. moduleName:consts.projectConst.QUANTITY_DETAIL,
  176. data:{
  177. doc:newrecode,
  178. resort:true,
  179. update_task:update_task
  180. }
  181. };
  182. result.returndata =returndata
  183. return result;
  184. }catch (error){
  185. console.log(error)
  186. result.err;
  187. return result
  188. }
  189. }
  190. function getUpdateReferenceTask(quantity_detail_List,seq,re) {
  191. let update_task=[];
  192. for(let q of quantity_detail_List){
  193. let need_update =false;
  194. let newReg = q.regex;
  195. let newReferenceIndex;
  196. if(q.referenceIndexs.length>0){
  197. for (let i =0;i< q.referenceIndexs.length;i++){
  198. if(q.referenceIndexs[i]>seq){
  199. newReg = replaceAll('C'+q.referenceIndexs[i],'C'+(q.referenceIndexs[i]+re),newReg);
  200. newReg = replaceAll('c'+q.referenceIndexs[i],'c'+(q.referenceIndexs[i]+re),newReg);
  201. q.referenceIndexs[i] +=re;
  202. need_update = true;
  203. }
  204. }
  205. }
  206. if(need_update){
  207. newReferenceIndex = q.referenceIndexs;
  208. let task ={
  209. query:{
  210. ID:q.ID,
  211. projectID:q.projectID
  212. },
  213. doc:{
  214. regex:newReg,
  215. referenceIndexs:newReferenceIndex
  216. }
  217. }
  218. update_task.push(task);
  219. }
  220. }
  221. return update_task;
  222. }
  223. async function createNormalRecode(doc) {
  224. let result ={};
  225. result.newRecord= await quantity_detail_model.create(doc);
  226. return result;
  227. }
  228. async function insertRecodeWithReg (doc) {
  229. let returnObjec={}
  230. try {
  231. let decimal =await decimal_facade.getProjectDecimal(doc.projectID);
  232. let regex = doc.regex.toUpperCase();
  233. let referenceIndexs = doc.referenceIndexs;
  234. let detailList = await getDatailList(doc,returnObjec);
  235. if(!doc.hasOwnProperty('result')){//前端已结计算完了,后端就不用再计算了
  236. doc.result =getEvalResult(referenceIndexs,detailList,regex,decimal);
  237. }
  238. let refreshQuantity =false;
  239. if(doc.refreshQuantity==true){
  240. refreshQuantity = true;
  241. }
  242. delete doc.refreshQuantity;
  243. let newRecord = await quantity_detail_model.create(doc) ;
  244. detailList.push(newRecord);
  245. if(refreshQuantity==true){
  246. let data = await summateResults(doc,detailList,decimal);
  247. returnObjec.node.data = data;
  248. }
  249. returnObjec.newRecord = newRecord;
  250. return returnObjec;
  251. }catch (error){
  252. console.log(error);
  253. throw new Error('输入的表达式有误,请重新输入!');
  254. }
  255. }
  256. async function doIsSummationUpdate(query,doc) {
  257. let returnObjec={query:query,doc:doc};
  258. let decimal =await decimal_facade.getProjectDecimal(query.projectID);
  259. let refreshQuantity=false;
  260. if(query.refreshQuantity==true){
  261. refreshQuantity=true;
  262. }
  263. delete query.refreshQuantity;
  264. await quantity_detail_model.update(query,doc);
  265. let detailList = await getDatailList(query,returnObjec);
  266. if(refreshQuantity==true){
  267. let data = await summateResults(query,detailList,decimal);
  268. returnObjec.node.data = data;
  269. }
  270. return returnObjec;
  271. }
  272. async function getDatailList(query,resultObject) {
  273. let detailList = [];
  274. let node={};
  275. if(query.hasOwnProperty('rationID')){
  276. detailList = await quantity_detail_model.find({'projectID':query.projectID,'rationID':query.rationID}).sort('seq').exec();
  277. node.type = consts.projectConst.RATION;
  278. node.ID = query.rationID;
  279. }else {
  280. detailList = await quantity_detail_model.find({'projectID':query.projectID,'billID':query.billID}).sort('seq').exec();
  281. node.type = consts.projectConst.BILLS;
  282. node.ID=query.billID;
  283. }
  284. resultObject.node = node;
  285. return detailList;
  286. }
  287. function updateReferenceRecode(index,detailList,updateTasks) {
  288. for(let d of detailList){
  289. if(_.includes(d.referenceIndexs,index)){
  290. let tResult = getEvalResult(d.referenceIndexs,detailList,d.regex);
  291. let t = {
  292. query:{
  293. ID:d.ID,
  294. projectID:d.projectID
  295. },
  296. doc:{
  297. result:tResult
  298. }
  299. };
  300. d.result = tResult;
  301. updateTasks.push(t);
  302. updateReferenceRecode(d.seq+1,detailList,updateTasks);
  303. }
  304. }
  305. }
  306. async function summateResults (query,detailList,decimal) {
  307. let quantity = 0;
  308. let doc = {};
  309. decimal = decimal?decimal:await decimal_facade.getProjectDecimal(query.projectID);
  310. for(let d of detailList){
  311. if(d.isSummation==1){
  312. let result = d.result==null||d.result==undefined?0:d.result;
  313. quantity+=result;
  314. }
  315. }
  316. if(query.hasOwnProperty('rationID')){
  317. let ration = await ration_model.findOne({'ID':query.rationID,'projectID':query.projectID,deleteInfo: null});
  318. let bill = await bill_model.findOne({'projectID':query.projectID,deleteInfo: null,"ID":ration.billsItemID});
  319. let bill_decimal = await decimal_facade.getBillsQuantityDecimal(query.projectID,bill.unit);
  320. let bill_quantity = scMathUtil.roundForObj(bill.quantity,bill_decimal);
  321. let contain = bill_quantity==0?0:scMathUtil.roundForObj(quantity/bill_quantity,decimal.process);
  322. let r_quantity = quantity;
  323. quantity = getQuantityByUnit(quantity,ration.unit);
  324. quantity = scMathUtil.roundTo(quantity, -decimal.ration.quantity);
  325. doc={quantity:quantity,isFromDetail:1,quantityEXP:'GCLMXHJ',contain:contain};
  326. await ration_model.update({'ID':query.rationID,'projectID':query.projectID,deleteInfo: null},doc);
  327. doc.r_quantity = r_quantity;
  328. }else {
  329. let bill = await bill_model.findOne({'ID':query.billID,'projectID':query.projectID,deleteInfo: null});
  330. decimal = await decimal_facade.getBillsQuantityDecimal(query.projectID,bill.unit);
  331. // quantity = getQuantityByUnit(quantity,bill.unit);
  332. quantity = scMathUtil.roundTo(quantity, -decimal);
  333. doc = {quantity:quantity,isFromDetail:1,quantityEXP:'GCLMXHJ'};
  334. await bill_model.update({'ID':query.billID,'projectID':query.projectID,deleteInfo: null},doc);
  335. }
  336. return doc
  337. }
  338. function getQuantityByUnit(quantity,unit) {
  339. if(unit){
  340. let times = parseInt(unit);
  341. if(isNaN(times)){
  342. times = 1
  343. }
  344. quantity = quantity/times;
  345. }
  346. return quantity;
  347. }
  348. function getEvalResult(referenceIndexs,detailList,regex,decimal={}) {
  349. try {
  350. decimal = decimal.quantity_detail?decimal.quantity_detail:4;
  351. for(let i of referenceIndexs){
  352. regex = replaceReference(i,detailList,regex)
  353. }
  354. console.log('replace all C reference -----'+regex);
  355. regex =replaceSqr(regex);
  356. console.log('replace all sqar reference -----'+regex);
  357. return scMathUtil.roundTo(eval(regex), -decimal);
  358. }catch (error){
  359. console.log(error);
  360. throw new Error('输入的表达式有误,请重新输入!');
  361. }
  362. }
  363. function generateUpdateTaks(updateTasks) {
  364. var tasks=[];
  365. for(let u of updateTasks){
  366. let t ={
  367. updateOne:{
  368. filter:u.query,
  369. update: u.doc
  370. }
  371. }
  372. tasks.push(t);
  373. }
  374. return tasks;
  375. }
  376. function replaceReference(index,detailList,str) {
  377. str=str.toUpperCase();
  378. let rstr= detailList[index-1].regex==null?'0':'('+detailList[index-1].regex+')';
  379. str=replaceAll('C'+index,rstr,str);
  380. if(detailList[index-1].referenceIndexs.length>0){
  381. for (let i of detailList[index-1].referenceIndexs){
  382. str =replaceReference(i,detailList,str);
  383. }
  384. }
  385. return str;
  386. }
  387. function replaceAll (FindText, RepText,str) {
  388. let regExp = new RegExp(FindText, "g");
  389. return str.replace(regExp, RepText);
  390. }
  391. function replaceSqr(text) {
  392. var squarRegex = /\([^\^]+\)\^\d+/g;
  393. var sqararr = text.match(squarRegex);
  394. var squarRegex2 = /C[0-9]+\^\d+|[0-9]+([.]{1}[0-9]+){0,1}\^\d+/g; //匹配没有括号的
  395. var sqararr2=text.match(squarRegex2);
  396. if(sqararr){
  397. text=converSqrByArr(sqararr,text);
  398. }
  399. if(sqararr2){
  400. text=converSqrByArr(sqararr2,text);
  401. }
  402. return text;
  403. }
  404. function converSqrByArr (sqararr,text) {
  405. var temp = text;
  406. sqararr.forEach(function (item) {
  407. var arr = item.split('\^');
  408. var y = parseInt(arr[1]);
  409. var x_arr = [];
  410. for (var i = 0; i < y; i++) {
  411. x_arr.push(arr[0]);
  412. }
  413. var temStr = x_arr.join('*');
  414. temp = temp.replace(item, temStr);
  415. });
  416. return temp;
  417. };
  418. function update_quantity_detail(user_id,datas) {
  419. if(datas.updateFunction){
  420. return updateFunctionMap[datas.updateFunction](user_id,datas);
  421. }else {
  422. return normalUpdate(user_id,datas);
  423. }
  424. }
  425. async function deleteRecode(doc) {
  426. let resultObject = {};
  427. let decimal =await decimal_facade.getProjectDecimal(doc.projectID);
  428. let query = {
  429. projectID:doc.projectID,
  430. seq : { $gt: doc.seq }
  431. }
  432. if(doc.hasOwnProperty('rationID')){
  433. query.rationID = doc.rationID;
  434. }else {
  435. query.billID = doc.billID;
  436. }
  437. let quantity_detail_List = await getDatailList(doc,resultObject);
  438. let update_task = getUpdateReferenceTask(quantity_detail_List,doc.seq,-1);
  439. await quantity_detail_model.update(query,{$inc:{seq:-1}},{multi: true});
  440. if(update_task.length>0){
  441. await quantity_detail_model.bulkWrite(generateUpdateTaks(update_task));
  442. }
  443. await quantity_detail_model.deleteOne({ID:doc.ID,projectID:doc.projectID});
  444. _.remove(quantity_detail_List,{ID:doc.ID,projectID:doc.projectID});
  445. //更新节点信息
  446. let n_data = await summateResults(query,quantity_detail_List,decimal);
  447. resultObject.node.data = n_data;
  448. let r_data ={
  449. doc:doc,
  450. resort:true,
  451. update_task:update_task,
  452. updateTpye:commonConsts.UT_DELETE
  453. };
  454. resultObject.data = r_data;
  455. return resultObject;
  456. }
  457. function getData(projectID, callback) {
  458. quantity_detail_model.find({'projectID':projectID}).sort('seq').exec((err,datas)=>{
  459. if(err){
  460. callback(1, '', null);
  461. }else {
  462. callback(0, consts.projectConst.QUANTITY_DETAIL, datas);
  463. }
  464. })
  465. }
  466. function save (user_id, datas, callback) {
  467. let operations=[];
  468. if(_.isArray(datas)){
  469. for(let i=0;i<datas.length;i++){
  470. operations.push(operationMap[datas[i].updateType](user_id,datas[i]));
  471. }
  472. }else {
  473. operations.push(operationMap[datas.updateType](user_id,datas));
  474. }
  475. async_n.parallel(operations,function (err,results) {
  476. if(err){
  477. callback(err,'');
  478. }else {
  479. if(results.length==1){
  480. callback(null,results[0])
  481. }else {
  482. callback(null,results)
  483. }
  484. }
  485. })
  486. }
  487. function deleteByRation(data) {
  488. return function (callback) {
  489. quantity_detail_model.deleteMany({projectID: data.projectID, rationID: data.ID},(err,result)=>{
  490. commonCallback(callback,result,err);
  491. });
  492. }
  493. }
  494. function deleteByBill(data) {
  495. return function (callback) {
  496. console.log({projectID: data.projectID, billID: data.ID});
  497. quantity_detail_model.deleteMany({projectID: data.projectID, billID: data.ID},(err,result)=>{
  498. commonCallback(callback,result,err);
  499. });
  500. }
  501. }
  502. async function deleteByQuery(query) {
  503. return await quantity_detail_model.deleteMany(query);
  504. }
  505. function quantityEditChecking(doc,type,functions) {
  506. if(doc.updateType == commonConsts.UT_UPDATE&&doc.updateData.hasOwnProperty('isFromDetail')&&doc.updateData.isFromDetail==0) {
  507. if(type=='bills'){
  508. functions.push(deleteByBill(doc.updateData));
  509. }else if(type=='ration'){
  510. functions.push(deleteByRation(doc.updateData));
  511. }
  512. }
  513. }
  514. function commonCallback(callback,result,err) {
  515. if(err){
  516. callback(err,'');
  517. }else {
  518. callback(null,result);
  519. }
  520. }