bills_controller.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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. const uuidV1 = require('uuid/v1');
  19. const billType ={
  20. DXFY:1,//大项费用
  21. FB:2,//分部
  22. FX:3,//分项
  23. BILL:4,//清单
  24. BX:5//补项
  25. };
  26. // 上传控件
  27. const multiparty = require("multiparty");
  28. const fs = require("fs");
  29. // excel解析
  30. const excel = require("node-xlsx");
  31. //统一回调函数
  32. var callback = function(req, res, err, message, data){
  33. res.json({error: err, message: message, data: data});
  34. };
  35. module.exports = {
  36. getData: function(req, res){
  37. var data = JSON.parse(req.body.data);
  38. billsData.getData(data.projectId, function(err, message, billsList){
  39. if (err === 0) {
  40. callback(req, res, err, message, billsList);
  41. } else {
  42. callback(req, res, err, message, null);
  43. }
  44. });
  45. },
  46. getItemTemplate: function(req, res){
  47. //var data = JSON.parse(req.body.data);
  48. billsData.getItemTemplate(function(err, message, billsItem){
  49. if (billsItem) {
  50. callback(req, res, err, message, billsItem);
  51. } else {
  52. callback(req, res, err, message, null);
  53. }
  54. });
  55. },
  56. allocIDs: function(req, res){
  57. billsData.allocIDs(function(err, message, data){
  58. if (err) {
  59. callback(req, res, err, message, data);
  60. } else {
  61. callback(req, res, err, message, null);
  62. }
  63. });
  64. },
  65. //zhong 2017-9-1
  66. updateCharacterContent: function (req, res) {
  67. let data = JSON.parse(req.body.data);
  68. let findSet = data.findSet,
  69. updateObj = data.updateObj,
  70. txtObj = data.txtObj;
  71. billsData.updateCharacterContent(findSet, updateObj, txtObj, function (err, message) {
  72. callback(req, res, err, message, null);
  73. });
  74. },
  75. updateBill: async function(request, response) {
  76. const data = JSON.parse(request.body.data);
  77. const findSet = data.findSet;
  78. const updateData = data.updateData;
  79. let settingData = {};
  80. // 筛选出要保存在项目属性的设置
  81. for (const index in updateData) {
  82. if (updateData[index].field === 'addRule') {
  83. settingData = updateData[index].value;
  84. delete updateData[index];
  85. }
  86. }
  87. // 更新项目属性
  88. const propertyUpdateData = {
  89. property: 'addRule',
  90. data: settingData
  91. };
  92. const projectResult = await ProjectsData.updateProjectProperty(findSet.projectID, propertyUpdateData);
  93. const result = await billsData.updateBill(findSet, updateData);
  94. const message = !result || !projectResult ? '修改失败' : '修改成功';
  95. const err = !result || !projectResult ? 1 : 0;
  96. callback(request, response, err, message, null);
  97. },
  98. singleDelete:async function(req, res){
  99. let result={
  100. error:0
  101. }
  102. try {
  103. let data = req.body.data;
  104. data = JSON.parse(data);
  105. let tasks = generateSingleDeleteTasks(data);
  106. let resultData= await billsData.model.bulkWrite(tasks);
  107. //删除工程量明细
  108. await quantity_detail.deleteByQuery({projectID: data.projectID, billID: data.ID}) ;
  109. result.data=resultData;
  110. }catch (err){
  111. logger.err(err);
  112. result.error=1;
  113. result.message = err.message;
  114. }
  115. res.json(result);
  116. },
  117. multiDelete:async function(req, res){
  118. let result={
  119. error:0
  120. };
  121. try {
  122. let data = req.body.data;
  123. data = JSON.parse(data);
  124. result.data=await doBillsOrRationsDelete(data);
  125. }catch (err){
  126. logger.err(err);
  127. result.error=1;
  128. result.message = err.message;
  129. }
  130. res.json(result);
  131. },
  132. getSectionInfo:async function(req, res){
  133. let result={
  134. error:0
  135. }
  136. try {
  137. let data = req.body.data;
  138. data = JSON.parse(data);
  139. let sectionInfo= await bill_facade.getSectionInfo(data);
  140. result.data=sectionInfo;
  141. }catch (err){
  142. logger.err(err);
  143. result.error=1;
  144. result.message = err.message;
  145. }
  146. res.json(result);
  147. },
  148. reorganizeFBFX:async function(req,res){
  149. let result={
  150. error:0
  151. }
  152. try {
  153. let data = req.body.data;
  154. data = JSON.parse(data);
  155. let reorganizeResult= await bill_facade.reorganizeFBFX(data);
  156. result.data=reorganizeResult;
  157. }catch (err){
  158. logger.err(err);
  159. result.error=1;
  160. result.message = err.message;
  161. }
  162. res.json(result);
  163. },
  164. pasteBlock:async function(req,res){
  165. let result={
  166. error:0
  167. };
  168. try {
  169. let data = req.body.data;
  170. data = JSON.parse(data);
  171. let pasteResult = await bill_facade.pasteBlock(data);
  172. result.data = pasteResult;
  173. }catch (err){
  174. logger.err(err);
  175. result.error=1;
  176. result.message = err.message;
  177. }
  178. res.json(result);
  179. },
  180. //下载导入清单示例
  181. downloadExample: async function(request, response) {
  182. try {
  183. const filePath = './public/static/uploadExample.xlsx';
  184. const stats = fs.statSync(filePath);
  185. // 下载相关header
  186. response.set({
  187. 'Content-Type': 'application/octet-stream',
  188. 'Content-Disposition': 'attachment; filename=uploadExample.xlsx',
  189. 'Content-Length': stats.size
  190. });
  191. fs.createReadStream(filePath).pipe(response);
  192. } catch (error) {
  193. response.end(error);
  194. }
  195. },
  196. upload: async function(req, res){
  197. let responseData = {
  198. err: 0,
  199. msg: '',
  200. data: null
  201. };
  202. const allowHeader = ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
  203. const uploadOption = {
  204. uploadDir: './public'
  205. };
  206. const form = new multiparty.Form(uploadOption);
  207. let uploadFullName;
  208. form.parse(req, async function(err, fields, files) {
  209. try{
  210. const projectID = fields.projectID !== undefined && fields.projectID.length > 0 ?
  211. parseInt(fields.projectID[0]) : 0;
  212. if (projectID <= 0) {
  213. throw '参数错误';
  214. }
  215. const file = files.file !== undefined ? files.file[0] : null;
  216. if (err || file === null) {
  217. throw '上传失败';
  218. }
  219. // 判断类型
  220. if (file.headers['content-type'] === undefined || allowHeader.indexOf(file.headers['content-type']) < 0) {
  221. throw '不支持该类型';
  222. }
  223. // 重命名文件名
  224. uploadFullName = uploadOption.uploadDir + '/' + file.originalFilename;
  225. fs.renameSync(file.path, uploadFullName);
  226. const sheet = excel.parse(uploadFullName);
  227. if (sheet[0] === undefined || sheet[0].data === undefined) {
  228. throw 'excel没有对应数据';
  229. }
  230. //导入的数据是否含有固定行(分部分项、施工技术措施项目、施工组织措施项目,通过文件名判断)
  231. let flag = getImportFlag(file.originalFilename);
  232. if(!flag){
  233. throw 'excel数据错误';
  234. }
  235. let fixedBill = await billsData.model.findOne({projectID: projectID, 'flags.flag': flag, deleteInfo: null});
  236. let insertFixedBill = null;
  237. //导入xx措施项目,若不存在此固定清单,则先插入相关固定清单
  238. if(!fixedBill){
  239. //分部分项工程(不可删除)应存在
  240. if(flag === fixedFlag.SUB_ENGINERRING){
  241. throw '项目不存在分部分项工程'
  242. }
  243. //措施项目是否存在
  244. let csxm = await billsData.model.findOne({projectID: projectID, 'flags.flag': fixedFlag.MEASURE, deleteInfo: null});
  245. if(!csxm){
  246. throw '项目不存在措施项目'
  247. }
  248. //插入清单固定行(施工技术措施项目、施工组织措施项目可删除)
  249. insertFixedBill = {projectID: projectID, name: flag === fixedFlag.CONSTRUCTION_TECH ? '施工技术措施项目' : '施工组织措施项目', code: '1',
  250. ID: uuidV1(), NextSiblingID: -1, ParentID: csxm.ID, flags: [{fieldName: 'fixed', flag: flag}], type: billType.BILL};
  251. //更新前节点
  252. let preDatas = await billsData.model.find({projectID: projectID, ParentID: csxm.ID, deleteInfo: null});
  253. for(let preData of preDatas){
  254. if(preData.NextSiblingID == -1){
  255. await billsData.model.update({ID: preData.ID}, {$set: {NextSiblingID: insertFixedBill.ID}});
  256. break;
  257. }
  258. }
  259. await billsData.model.create(insertFixedBill);
  260. fixedBill = insertFixedBill;
  261. }
  262. console.log(`fixedBill--------------`);
  263. console.log(fixedBill);
  264. //匹配的清单库
  265. const billsLibId = fields.billsLibId !== undefined && fields.billsLibId.length > 0 && fields.billsLibId[0]? parseInt(fields.billsLibId[0]) : null;
  266. let stdBills = [], stdJobs = [], stdCharacters = [];
  267. if(billsLibId){
  268. stdBills = await stdBillsModel.find({billsLibId: billsLibId, deleted: false}, '-_id code jobs items engineering');
  269. stdJobs = await stdBillJobsModel.find({billsLibId: billsLibId, deleted: false});
  270. stdCharacters = await stdBillCharacterModel.find({billsLibId: billsLibId, deleted: false});
  271. }
  272. //将excel数据转换成清单树结构数据
  273. let insertDatas = parseToBillData(getValidImportData(sheet[0].data, fixedBill), getColMapping(sheet[0].data), fixedBill, projectID, {stdBills: stdBills, stdJobs: stdJobs, stdCharacters: stdCharacters});
  274. //删除相关数据
  275. let deleteDatas = await billsData.deepDeleteBill([fixedBill], req.session.sessionUser.id);
  276. //新增清单数据
  277. await billsData.importBills(insertDatas);
  278. //返回数据以更新前端
  279. if(insertFixedBill){
  280. insertDatas.push(insertFixedBill);
  281. }
  282. responseData.data = {fixedBill: fixedBill, insert: {bill: insertDatas, ration: []}, remove: {bill: deleteDatas.bill, ration: deleteDatas.ration}};
  283. //删除暂存文件
  284. fs.unlink(uploadFullName);
  285. res.json(responseData);
  286. }
  287. catch (error){
  288. if(fs.existsSync(uploadFullName)){
  289. fs.unlink(uploadFullName);
  290. }
  291. responseData.err = 1;
  292. responseData.msg = error;
  293. res.json(responseData);
  294. }
  295. });
  296. }
  297. };
  298. //提取excel表头列对应数据
  299. function getColMapping(sheetData){
  300. //获取表头
  301. let headRow = [];
  302. for(let rData of sheetData) {
  303. if (rData[0] && rData[0].toString().replace(/\s/g, '') === '序号') {
  304. headRow = rData;
  305. break;
  306. }
  307. }
  308. //获取表头列与列号对应关系
  309. let colMapping = {};
  310. for(let c = 0; c < headRow.length; c++){
  311. if(headRow[c]){
  312. headRow[c] = headRow[c].toString().replace(/\s/g, '');
  313. switch(headRow[c]){
  314. case '序号': colMapping.serialNo = c; break;
  315. case '项目编码': colMapping.code = c; break;
  316. case '项目名称': colMapping.name = c; break;
  317. case '项目特征': colMapping.itemCharacterText = c; break;
  318. case '计量单位': colMapping.unit = c; break;
  319. case '工程量': colMapping.quantity = c; break;
  320. }
  321. }
  322. }
  323. return colMapping;
  324. }
  325. function rowExistData(rowData){
  326. for(let cData of rowData){
  327. if(cData !== undefined && cData !== ''){
  328. return true;
  329. }
  330. }
  331. return false;
  332. }
  333. //提取excel表数据中的有效数据(去表头表尾,提取其中的excel数据)(根据fixedBill获取栏头占行数)
  334. function getValidImportData(sheetData, fixedBill){
  335. let withingD = false;
  336. let validData = [];
  337. for(let r = 0; r < sheetData.length; r++){
  338. let rData = sheetData[r];
  339. if(rData[0]){
  340. //首列去空格
  341. rData[0] = rData[0].toString().replace(/\s/g, '');
  342. //表头
  343. if(rData[0] === '序号'){
  344. withingD = true;
  345. if(fixedBill.name !== '施工组织措施项目'){
  346. r++;
  347. }
  348. continue;
  349. }
  350. //表尾
  351. else if(rData[0] === '本页小计' || rData[0] === '合计'){
  352. withingD = false;
  353. }
  354. }
  355. if(withingD && rowExistData(rData)){
  356. validData.push(rData);
  357. }
  358. }
  359. return validData;
  360. }
  361. function getImportFlag(sheetName){
  362. const fixedItem = {'分部分项': fixedFlag.SUB_ENGINERRING, '施工技术措施项目': fixedFlag.CONSTRUCTION_TECH, '施工组织措施项目': fixedFlag.CONSTRUCTION_ORGANIZATION};
  363. for(let flag in fixedItem){
  364. if(sheetName.includes(flag)){
  365. return fixedItem[flag];
  366. }
  367. }
  368. return null;
  369. }
  370. //excel数据转换成清单数据
  371. function parseToBillData(validData, colMapping, fixedBill, projectID, stdData){
  372. let rst = [];
  373. let billIdx = {};
  374. let preRootID = -1,
  375. preLeafID = -1,
  376. preID = -1;
  377. //合并了项目特征,且行有数据
  378. function isRoot(rData){
  379. return rData[colMapping.itemCharacterText] !== undefined && rData[colMapping.itemCharacterText] === '' && rowExistData(rData);
  380. }
  381. //不合并且有序号
  382. function isLeaf(rData){
  383. return (rData[colMapping] === undefined || rData[colMapping] !== '') && rData[colMapping.serialNo] && rData[colMapping.serialNo] !== '';
  384. }
  385. //续数据,上一行数据是有效节点且无序号
  386. function isExtend(preData, rData){
  387. return preData && (isRoot(preData) || isLeaf(preData)) && !isRoot(rData) && (rData[colMapping.serialNo] === undefined || rData[colMapping.serialNo] === '');
  388. }
  389. function getBillType(rData, flag){
  390. if(flag === fixedFlag.CONSTRUCTION_TECH || flag === fixedFlag.CONSTRUCTION_ORGANIZATION){
  391. return billType.BILL;
  392. }
  393. else if(flag === fixedFlag.SUB_ENGINERRING){
  394. return isLeaf(rData) ? billType.FX : billType.FB;
  395. }
  396. return null;
  397. }
  398. //excel数据与标准库数据匹配,根据清单前九位编码匹配,匹配成功则获取标准清单对应的工程专业、特征及内容
  399. function matchStdBill(excelBill, stdData){
  400. let isMatch = false;
  401. let regExp = /^\d{12}$/g;
  402. if(regExp.test(excelBill.code)){
  403. let nineCode = excelBill.code.substr(0, 9);
  404. for(let stdBill of stdData.stdBills){
  405. //set programID
  406. if(nineCode == stdBill.code){
  407. isMatch = true;
  408. excelBill.programID = stdBill.engineering ? stdBill.engineering : null;
  409. //set jobContent and itemCharacter
  410. let tempJob = [], tempCharacter = [];
  411. for(let billJob of stdBill.jobs){
  412. for(let stdJob of stdData.stdJobs) {
  413. if (billJob.id == stdJob.id) {
  414. tempJob.push({isChecked: false, serialNo: billJob.serialNo, content: stdJob.content});
  415. }
  416. }
  417. }
  418. for(let billCharacter of stdBill.items){
  419. for(let stdCharacter of stdData.stdCharacters){
  420. if(billCharacter.id == stdCharacter.id){
  421. let eigenvalue = [];
  422. for(let eValue of stdCharacter.itemValue){
  423. eigenvalue.push({isSelected: false, value: eValue.value});
  424. }
  425. tempCharacter.push({isChecked: false, serialNo: billCharacter.serialNo, character: stdCharacter.content, eigenvalue: eigenvalue});
  426. }
  427. }
  428. }
  429. excelBill.jobContent = tempJob;
  430. excelBill.itemCharacter = tempCharacter;
  431. }
  432. }
  433. }
  434. if(!isMatch && excelBill.type === billType.FX){//分项在标准清单中不匹配,则识别为补项
  435. excelBill.type = billType.BX;
  436. }
  437. }
  438. for(let r = 0; r < validData.length; r++){
  439. let preData = validData[r-1],
  440. rData = validData[r];
  441. if(fixedBill.flags[0].flag == fixedFlag.CONSTRUCTION_TECH && rData[colMapping.name] === '施工技术措施项目'
  442. || fixedBill.flags[0].flag == fixedFlag.CONSTRUCTION_ORGANIZATION && rData[colMapping.name] === '施工组织措施项目'){
  443. continue;
  444. }
  445. //过滤无效数据
  446. if(!isRoot(rData) && !isLeaf(rData) && !isExtend(preData, rData)){
  447. continue;
  448. }
  449. if(isExtend(preData, rData)){
  450. let preBill = billIdx[preID];
  451. //合并续数据
  452. if(preBill){
  453. preBill.code += rData[colMapping.code] ? rData[colMapping.code] : '';
  454. preBill.name += rData[colMapping.name] ? rData[colMapping.name] : '';
  455. preBill.itemCharacterText += rData[colMapping.itemCharacterText] ? rData[colMapping.itemCharacterText] : '';
  456. preBill.unit += rData[colMapping.unit] ? rData[colMapping.unit] : '';
  457. preBill.quantity += rData[colMapping.quantity] ? rData[colMapping.quantity] : '';
  458. }
  459. }
  460. else {
  461. let newID = uuidV1();
  462. let pID = -1;
  463. let preBill = null;
  464. if(isRoot(rData)){
  465. pID = fixedBill.ID;
  466. preBill = billIdx[preRootID];
  467. }
  468. else if(isLeaf(rData)){
  469. pID = preRootID !== -1 ? preRootID : fixedBill.ID;
  470. preBill = billIdx[preLeafID];
  471. }
  472. //set bill data
  473. billIdx[newID] = {
  474. ID: newID, ParentID: pID, NextSiblingID: -1,
  475. code: rData[colMapping.code] ? rData[colMapping.code] : '',
  476. name: rData[colMapping.name] ? rData[colMapping.name] : '',
  477. itemCharacterText: rData[colMapping.itemCharacterText] ? rData[colMapping.itemCharacterText] : '',
  478. itemCharacter: [],
  479. jobContentText: '',
  480. jobContent: [],
  481. programID: null,
  482. unit: rData[colMapping.unit] ? rData[colMapping.unit] : '',
  483. quantity: rData[colMapping.quantity] ? rData[colMapping.quantity] : '',
  484. //安全文明
  485. flags: fixedBill.flags[0].flag === fixedFlag.CONSTRUCTION_ORGANIZATION && (rData[colMapping.name] === '安全文明施工专项费用' || rData[colMapping.name] === '安全文明施工费') ?
  486. [{fieldName: 'fixed', flag: fixedFlag.SAFETY_CONSTRUCTION}] : [],
  487. fees: [],
  488. projectID: projectID,
  489. type: getBillType(rData, fixedBill.flags[0].flag)};
  490. //match stdBill and reset programID、jobContent、itemCharacter
  491. matchStdBill(billIdx[newID], stdData);
  492. //update preBill NextSibling
  493. if(preBill){
  494. preBill.NextSiblingID = newID;
  495. }
  496. //set new preID
  497. preID = newID;
  498. preRootID = isRoot(rData) ? newID : preRootID;
  499. preLeafID = isLeaf(rData) ? newID : preLeafID;
  500. }
  501. }
  502. for(let i in billIdx){
  503. rst.push(billIdx[i]);
  504. }
  505. return rst;
  506. }
  507. async function doBillsOrRationsDelete(data) {
  508. let billTask = [];
  509. let deleteBillIDs = [];
  510. let rationTask=[];
  511. let deleteRationIDs=[];
  512. let qd_query=null;
  513. let sub_query=null;
  514. if(data['bills']){
  515. billTask = generateUpdateTasks(data['bills'],data.projectID,data.user_id);
  516. for(let b_key in data['bills']){
  517. if(data['bills'][b_key]===true){
  518. deleteBillIDs.push(b_key+'');
  519. }
  520. }
  521. if(deleteBillIDs.length>0){
  522. qd_query={projectID: data.projectID, billID: {"$in": deleteBillIDs}};
  523. }
  524. }
  525. if(data['ration']){
  526. rationTask = generateUpdateTasks(data['ration'],data.projectID,data.user_id);
  527. for(let r_key in data['ration']){
  528. if(data['ration'][r_key]===true){
  529. deleteRationIDs.push(r_key+'');
  530. }
  531. }
  532. if(deleteRationIDs.length>0){
  533. if(qd_query==null){//说明没删除清单
  534. qd_query={projectID: data.projectID, rationID: {"$in": deleteRationIDs}};
  535. }else {
  536. qd_query={
  537. "$or":[
  538. {projectID: data.projectID, billID: {"$in": deleteBillIDs}},
  539. {projectID: data.projectID, rationID: {"$in": deleteRationIDs}}
  540. ]
  541. }
  542. }
  543. sub_query={projectID: data.projectID, rationID: {"$in": deleteRationIDs}};
  544. }
  545. }
  546. //先删除工程量明细
  547. if(qd_query!=null){
  548. await quantity_detail.deleteByQuery(qd_query) ;
  549. }
  550. if(sub_query!=null){
  551. await ration_coe.deleteMany(sub_query);//删除附注条件
  552. await ration_glj.deleteMany(sub_query);//删除定额工料机
  553. await rationInstallationModel.deleteMany(sub_query);//删除安装增加费
  554. }
  555. if(rationTask.length>0){
  556. await ration_model.model.bulkWrite(rationTask);//删除定额
  557. }
  558. if(billTask.length>0){
  559. await billsData.model.bulkWrite(billTask);//删除清单
  560. }
  561. return 'success';
  562. }
  563. function generateSingleDeleteTasks(data) {
  564. let updateData = data.updateData;
  565. updateData[data.ID]=true;
  566. let tasks = generateUpdateTasks(updateData,data.projectID,data.user_id);
  567. return tasks;
  568. }
  569. function generateUpdateTasks(data,projectID,user_id) {
  570. let tasks=[];
  571. let updateData = data;
  572. let deleteInfo={deleted: true, deleteDateTime: new Date(), deleteBy: user_id};
  573. for(let key in updateData){
  574. let task={
  575. updateOne:{
  576. filter:{
  577. ID:key,
  578. projectID:projectID
  579. }
  580. }
  581. };
  582. if(updateData[key]===true){
  583. task.updateOne.update={
  584. deleteInfo:deleteInfo
  585. };
  586. }else {
  587. task.updateOne.update=updateData[key];
  588. }
  589. tasks.push(task);
  590. }
  591. return tasks;
  592. }