bills_controller.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /**
  2. * Created by jimiz on 2017/4/7.
  3. */
  4. let mongoose = require('mongoose');
  5. var billsData = require('../models/bills');
  6. let ration_model = require('../models/ration');
  7. let ProjectsData = require('../../pm/models/project_model').project;
  8. let logger = require("../../../logs/log_helper").logger;
  9. let quantity_detail = require("../facade/quantity_detail_facade");
  10. let bill_facade = require("../facade/bill_facade");
  11. let ration_glj = mongoose.model('ration_glj');
  12. let ration_coe = mongoose.model('ration_coe');
  13. let rationInstallationModel = mongoose.model('ration_installation');
  14. let stdBillsModel = mongoose.model('std_bills_lib_bills');
  15. let stdBillJobsModel = mongoose.model('std_bills_lib_jobContent');
  16. let stdBillCharacterModel = mongoose.model('std_bills_lib_itemCharacter');
  17. import fixedFlag from '../../common/const/bills_fixed';
  18. let LZString = require('lz-string');
  19. const uuidV1 = require('uuid/v1');
  20. const billType ={
  21. DXFY:1,//大项费用
  22. FB:2,//分部
  23. FX:3,//分项
  24. BILL:4,//清单
  25. BX:5//补项
  26. };
  27. //上传的09表、广联达表
  28. const uploadType = {lj: 'lj', gld: 'gld'};
  29. // 上传控件
  30. const multiparty = require("multiparty");
  31. const fs = require("fs");
  32. // excel解析
  33. const excel = require("node-xlsx");
  34. //统一回调函数
  35. var callback = function(req, res, err, message, data){
  36. res.json({error: err, message: message, data: data});
  37. };
  38. module.exports = {
  39. getData: function(req, res){
  40. var data = JSON.parse(req.body.data);
  41. billsData.getData(data.projectId, function(err, message, billsList){
  42. if (err === 0) {
  43. callback(req, res, err, message, billsList);
  44. } else {
  45. callback(req, res, err, message, null);
  46. }
  47. });
  48. },
  49. getItemTemplate: function(req, res){
  50. //var data = JSON.parse(req.body.data);
  51. billsData.getItemTemplate(function(err, message, billsItem){
  52. if (billsItem) {
  53. callback(req, res, err, message, billsItem);
  54. } else {
  55. callback(req, res, err, message, null);
  56. }
  57. });
  58. },
  59. allocIDs: function(req, res){
  60. billsData.allocIDs(function(err, message, data){
  61. if (err) {
  62. callback(req, res, err, message, data);
  63. } else {
  64. callback(req, res, err, message, null);
  65. }
  66. });
  67. },
  68. //zhong 2017-9-1
  69. updateCharacterContent: function (req, res) {
  70. let data = JSON.parse(req.body.data);
  71. let findSet = data.findSet,
  72. updateObj = data.updateObj,
  73. txtObj = data.txtObj;
  74. billsData.updateCharacterContent(findSet, updateObj, txtObj, function (err, message) {
  75. callback(req, res, err, message, null);
  76. });
  77. },
  78. updateBill: async function(request, response) {
  79. const data = JSON.parse(request.body.data);
  80. const findSet = data.findSet;
  81. const updateData = data.updateData;
  82. let settingData = {};
  83. // 筛选出要保存在项目属性的设置
  84. for (const index in updateData) {
  85. if (updateData[index].field === 'addRule') {
  86. settingData = updateData[index].value;
  87. delete updateData[index];
  88. }
  89. }
  90. /* // 更新项目属性
  91. const propertyUpdateData = {
  92. property: 'addRule',
  93. data: settingData
  94. };*/
  95. //const projectResult = await ProjectsData.updateProjectProperty(findSet.projectID, propertyUpdateData);
  96. const result = await billsData.updateBill(findSet, updateData);
  97. const message = !result ? '修改失败' : '修改成功';
  98. const err = !result ? 1 : 0;
  99. callback(request, response, err, message, null);
  100. },
  101. singleDelete:async function(req, res){
  102. let result={
  103. error:0
  104. }
  105. try {
  106. let data = req.body.data;
  107. data = JSON.parse(data);
  108. let tasks = generateSingleDeleteTasks(data);
  109. let resultData= await billsData.model.bulkWrite(tasks);
  110. //删除工程量明细
  111. await quantity_detail.deleteByQuery({projectID: data.projectID, billID: data.ID}) ;
  112. result.data=resultData;
  113. }catch (err){
  114. logger.err(err);
  115. result.error=1;
  116. result.message = err.message;
  117. }
  118. res.json(result);
  119. },
  120. multiDelete:async function(req, res){
  121. let result={
  122. error:0
  123. };
  124. try {
  125. let data = req.body.data;
  126. data = JSON.parse(data);
  127. result.data=await doBillsOrRationsDelete(data);
  128. }catch (err){
  129. logger.err(err);
  130. result.error=1;
  131. result.message = err.message;
  132. }
  133. res.json(result);
  134. },
  135. getSectionInfo:async function(req, res){
  136. let result={
  137. error:0
  138. }
  139. try {
  140. let data = req.body.data;
  141. data = JSON.parse(data);
  142. let sectionInfo= await bill_facade.getSectionInfo(data);
  143. result.data=sectionInfo;
  144. }catch (err){
  145. logger.err(err);
  146. result.error=1;
  147. result.message = err.message;
  148. }
  149. res.json(result);
  150. },
  151. reorganizeFBFX:async function(req,res){
  152. let result={
  153. error:0
  154. }
  155. try {
  156. let data = req.body.data;
  157. data = JSON.parse(data);
  158. let reorganizeResult= await bill_facade.reorganizeFBFX(data);
  159. result.data=reorganizeResult;
  160. }catch (err){
  161. logger.err(err);
  162. result.error=1;
  163. result.message = err.message;
  164. }
  165. res.json(result);
  166. },
  167. pasteBlock:async function(req,res){
  168. let result={
  169. error:0
  170. };
  171. try {
  172. let data = req.body.data;
  173. data = JSON.parse(data);
  174. let pasteResult = await bill_facade.pasteBlock(data);
  175. result.data = pasteResult;
  176. }catch (err){
  177. logger.err(err);
  178. result.error=1;
  179. result.message = err.message;
  180. }
  181. res.json(result);
  182. },
  183. //下载导入清单示例
  184. downloadExample: async function(request, response) {
  185. try {
  186. const filePath = './public/static/uploadExample.xlsx';
  187. const stats = fs.statSync(filePath);
  188. // 下载相关header
  189. response.set({
  190. 'Content-Type': 'application/octet-stream',
  191. 'Content-Disposition': 'attachment; filename=uploadExample.xlsx',
  192. 'Content-Length': stats.size
  193. });
  194. fs.createReadStream(filePath).pipe(response);
  195. } catch (error) {
  196. response.end(error);
  197. }
  198. },
  199. //导入清单
  200. import: async function(req, res){
  201. let responseData = {
  202. err: 0,
  203. msg: '',
  204. data: []
  205. };
  206. const form = new multiparty.Form();
  207. form.parse(req, async function(err, fields, files) {
  208. try{
  209. const projectID = fields.projectID !== undefined && fields.projectID.length > 0 ?
  210. parseInt(fields.projectID[0]) : 0;
  211. if (projectID <= 0) {
  212. throw '参数错误';
  213. }
  214. //导入清单数据
  215. let compressData = fields.compressData !== undefined && fields.compressData.length > 0 ?
  216. fields.compressData[0] : null;
  217. if(compressData === null){
  218. throw 'excel没有对应数据'
  219. }
  220. let importData = JSON.parse(LZString.decompressFromUTF16(compressData));
  221. //匹配的清单库
  222. let stdDateA = +new Date();
  223. const billsLibId = fields.billsLibId !== undefined && fields.billsLibId.length > 0 && fields.billsLibId[0]? parseInt(fields.billsLibId[0]) : null;
  224. let stdBills = [], stdJobs = [], stdCharacters = [];
  225. if(billsLibId){
  226. stdBills = await stdBillsModel.find({billsLibId: billsLibId, deleted: false}, '-_id code jobs items engineering billsLibId');
  227. stdJobs = await stdBillJobsModel.find({billsLibId: billsLibId, deleted: false});
  228. stdCharacters = await stdBillCharacterModel.find({billsLibId: billsLibId, deleted: false});
  229. }
  230. let stdData = {stdBills: stdBills, stdJobs: stdJobs, stdCharacters: stdCharacters};
  231. //导入表
  232. let importDateA = +new Date();
  233. for(let position in importData){
  234. if(importData[position].length > 0){
  235. let updateFrontData = await importSheet(position, importData[position], req.session.sessionUser.id, projectID, stdData);
  236. if(updateFrontData){
  237. responseData.data.push(updateFrontData);
  238. }
  239. }
  240. }
  241. let importDateB = +new Date();
  242. console.log(`导入时间: ${importDateB - importDateA}=========================================================================`);
  243. res.json(responseData);
  244. }
  245. catch (error){
  246. responseData.err = 1;
  247. console.log(error);
  248. responseData.msg = typeof error === 'object' ? '上传失败' : error;
  249. res.json(responseData);
  250. }
  251. });
  252. }
  253. };
  254. async function importSheet(position, excelBills, userID, projectID, stdData){
  255. //导入位置的有固定行
  256. let flag = getImportFlag(position);
  257. if(!flag){
  258. throw 'excel数据错误';
  259. }
  260. let fixedBill = await billsData.model.findOne({projectID: projectID, 'flags.flag': flag, deleteInfo: null});
  261. let insertFixedBill = null;
  262. //导入xx措施项目,若不存在此固定清单,则先插入相关固定清单
  263. if(!fixedBill){
  264. //分部分项工程(不可删除)应存在
  265. if(flag === fixedFlag.SUB_ENGINERRING){
  266. throw '项目不存在分部分项工程'
  267. }
  268. //措施项目是否存在
  269. let csxm = await billsData.model.findOne({projectID: projectID, 'flags.flag': fixedFlag.MEASURE, deleteInfo: null});
  270. if(!csxm){
  271. throw '项目不存在措施项目'
  272. }
  273. //插入清单固定行(施工技术措施项目、施工组织措施项目可删除)
  274. insertFixedBill = {projectID: projectID, name: flag === fixedFlag.CONSTRUCTION_TECH ? '施工技术措施项目' : '施工组织措施项目', code: '1',
  275. ID: uuidV1(), NextSiblingID: -1, ParentID: csxm.ID, flags: [{fieldName: 'fixed', flag: flag}], type: billType.BILL};
  276. //更新前节点
  277. let preDatas = await billsData.model.find({projectID: projectID, ParentID: csxm.ID, deleteInfo: null});
  278. for(let preData of preDatas){
  279. if(preData.NextSiblingID == -1){
  280. await billsData.model.update({ID: preData.ID}, {$set: {NextSiblingID: insertFixedBill.ID}});
  281. break;
  282. }
  283. }
  284. await billsData.model.create(insertFixedBill);
  285. fixedBill = insertFixedBill;
  286. }
  287. //将excel清单数据转换成完整清单数据(设置ParentID、匹配标准清单库)
  288. parseToCompleteBills(excelBills, fixedBill, stdData);
  289. //删除相关数据
  290. let deleteDatas = await billsData.deepDeleteBill([fixedBill], userID);
  291. //新增清单数据
  292. await billsData.importBills(excelBills);
  293. //返回数据以更新前端
  294. if(insertFixedBill){
  295. excelBills.push(insertFixedBill);
  296. }
  297. return {fixedBill: fixedBill, insert: {bill: excelBills, ration: []}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}};
  298. }
  299. function getImportFlag(position){
  300. const fixedItem = {'fbfx': fixedFlag.SUB_ENGINERRING, 'jscsxm': fixedFlag.CONSTRUCTION_TECH, 'zzcsxm': fixedFlag.CONSTRUCTION_ORGANIZATION};
  301. return fixedItem[position] ? fixedItem[position] : null;
  302. }
  303. function isDef(data){
  304. return typeof data !== 'undefined' && data !== null && data !== '';
  305. }
  306. //将前端解析生成的清单节点数据完善(ParentID、匹配标准清单)
  307. function parseToCompleteBills(excelBills, fixedBills, stdData){
  308. //设置清单ParentID
  309. let rootID = fixedBills ? fixedBills.ID: -1;
  310. for(let bills of excelBills){
  311. if(bills.nodeType === 'root'){
  312. rootID = bills.ID;
  313. bills.ParentID = fixedBills.ID;
  314. }
  315. else {
  316. bills.ParentID = rootID;
  317. }
  318. delete bills.nodeType;
  319. matchStdBill(bills, stdData);
  320. }
  321. //excel数据与标准库数据匹配,根据清单前九位编码匹配,匹配成功则获取标准清单对应的工程专业、特征及内容
  322. function matchStdBill(excelBill, stdData){
  323. let isMatch = false;
  324. let regExp = /^\d{12}$/g;
  325. if(regExp.test(excelBill.code)){
  326. let nineCode = excelBill.code.substr(0, 9);
  327. for(let stdBill of stdData.stdBills){
  328. //set programID
  329. if(nineCode == stdBill.code){
  330. isMatch = true;
  331. excelBill.programID = stdBill.engineering ? stdBill.engineering : null;
  332. excelBill.billsLibId = stdBill.billsLibId ? stdBill.billsLibId : null;
  333. //set jobContent and itemCharacter
  334. let tempJob = [], tempCharacter = [];
  335. for(let billJob of stdBill.jobs){
  336. for(let stdJob of stdData.stdJobs) {
  337. if (billJob.id == stdJob.id) {
  338. tempJob.push({isChecked: false, serialNo: billJob.serialNo, content: stdJob.content});
  339. }
  340. }
  341. }
  342. for(let billCharacter of stdBill.items){
  343. for(let stdCharacter of stdData.stdCharacters){
  344. if(billCharacter.id == stdCharacter.id){
  345. let eigenvalue = [];
  346. for(let eValue of stdCharacter.itemValue){
  347. eigenvalue.push({isSelected: false, value: eValue.value});
  348. }
  349. tempCharacter.push({isChecked: false, serialNo: billCharacter.serialNo, character: stdCharacter.content, eigenvalue: eigenvalue});
  350. }
  351. }
  352. }
  353. excelBill.jobContent = tempJob;
  354. excelBill.itemCharacter = tempCharacter;
  355. }
  356. }
  357. }
  358. if(!isMatch && excelBill.type === billType.FX){//分项不为空,同时在标准清单中不匹配,则识别为补项
  359. excelBill.type = billType.BX;
  360. }
  361. }
  362. }
  363. async function doBillsOrRationsDelete(data) {
  364. let billTask = [];
  365. let deleteBillIDs = [];
  366. let rationTask=[];
  367. let deleteRationIDs=[];
  368. let qd_query=null;
  369. let sub_query=null;
  370. if(data['bills']){
  371. billTask = generateUpdateTasks(data['bills'],data.projectID,data.user_id);
  372. for(let b_key in data['bills']){
  373. if(data['bills'][b_key]===true){
  374. deleteBillIDs.push(b_key+'');
  375. }
  376. }
  377. if(deleteBillIDs.length>0){
  378. qd_query={projectID: data.projectID, billID: {"$in": deleteBillIDs}};
  379. }
  380. }
  381. if(data['ration']){
  382. rationTask = generateUpdateTasks(data['ration'],data.projectID,data.user_id);
  383. for(let r_key in data['ration']){
  384. if(data['ration'][r_key]===true){
  385. deleteRationIDs.push(r_key+'');
  386. }
  387. }
  388. if(deleteRationIDs.length>0){
  389. if(qd_query==null){//说明没删除清单
  390. qd_query={projectID: data.projectID, rationID: {"$in": deleteRationIDs}};
  391. }else {
  392. qd_query={
  393. "$or":[
  394. {projectID: data.projectID, billID: {"$in": deleteBillIDs}},
  395. {projectID: data.projectID, rationID: {"$in": deleteRationIDs}}
  396. ]
  397. }
  398. }
  399. sub_query={projectID: data.projectID, rationID: {"$in": deleteRationIDs}};
  400. }
  401. }
  402. //先删除工程量明细
  403. if(qd_query!=null){
  404. await quantity_detail.deleteByQuery(qd_query) ;
  405. }
  406. if(sub_query!=null){
  407. await ration_coe.deleteMany(sub_query);//删除附注条件
  408. await ration_glj.deleteMany(sub_query);//删除定额工料机
  409. await rationInstallationModel.deleteMany(sub_query);//删除安装增加费
  410. }
  411. if(rationTask.length>0){
  412. await ration_model.model.bulkWrite(rationTask);//删除定额
  413. }
  414. if(billTask.length>0){
  415. await billsData.model.bulkWrite(billTask);//删除清单
  416. }
  417. return 'success';
  418. }
  419. function generateSingleDeleteTasks(data) {
  420. let updateData = data.updateData;
  421. updateData[data.ID]=true;
  422. let tasks = generateUpdateTasks(updateData,data.projectID,data.user_id);
  423. return tasks;
  424. }
  425. function generateUpdateTasks(data,projectID,user_id) {
  426. let tasks=[];
  427. let updateData = data;
  428. let deleteInfo={deleted: true, deleteDateTime: new Date(), deleteBy: user_id};
  429. for(let key in updateData){
  430. let task={
  431. updateOne:{
  432. filter:{
  433. ID:key,
  434. projectID:projectID
  435. }
  436. }
  437. };
  438. if(updateData[key]===true){
  439. task.updateOne.update={
  440. deleteInfo:deleteInfo
  441. };
  442. }else {
  443. task.updateOne.update=updateData[key];
  444. }
  445. tasks.push(task);
  446. }
  447. return tasks;
  448. }