ration_item.js 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  1. /**
  2. * Created by Tony on 2017/4/28.
  3. */
  4. const mongoose = require('mongoose');
  5. let async = require("async");
  6. let moment = require('moment');
  7. let counter = require('../../../public/counter/counter');
  8. let gljDao = require('./glj_repository');
  9. let rationRepositoryDao = require('./repository_map');
  10. const scMathUtil = require('../../../public/scMathUtil').getUtil();
  11. const rationItemModel = mongoose.model('std_ration_lib_ration_items');
  12. const stdRationLibModel = mongoose.model('std_ration_lib_map');
  13. const compleRationModel = mongoose.model('complementary_ration_items');
  14. import STDGLJListModel from '../../std_glj_lib/models/gljModel';
  15. var rationItemDAO = function(){};
  16. rationItemDAO.prototype.getRationItemsByLib = async function (rationRepId, showHint = null, returnFields = '') {
  17. let rationLib = await stdRationLibModel.findOne({ID: rationRepId, deleted: false});
  18. if(!rationLib){
  19. return [];
  20. }
  21. let startDate = new Date();
  22. let rations = await rationItemModel.find({rationRepId: rationRepId}, returnFields);
  23. console.log(`Date: ${new Date() - startDate}====================================`);
  24. if(!showHint){
  25. return rations;
  26. }
  27. else {
  28. const stdBillsLibListsModel = new STDGLJListModel();
  29. const stdGLJData = await stdBillsLibListsModel.getGljItemsByRepId(rationLib.gljLib, '-_id ID code name unit gljType');
  30. let gljMapping = {};
  31. for(let glj of stdGLJData){
  32. gljMapping[glj.ID] = glj;
  33. }
  34. //设置悬浮
  35. for(let ration of rations){
  36. let hintsArr = [];
  37. //对人材机进行排序
  38. ration.rationGljList.sort(function (a, b) {
  39. let gljA = gljMapping[a.gljId],
  40. gljB = gljMapping[b.gljId];
  41. if(gljA && gljB){
  42. let aV = gljA.gljType + gljA.code,
  43. bV = gljB.gljType + gljB.code;
  44. if(aV > bV) {
  45. return 1;
  46. } else if(aV < bV) {
  47. return -1;
  48. }
  49. }
  50. return 0;
  51. });
  52. for(let rationGlj of ration.rationGljList){
  53. let subGlj = gljMapping[rationGlj.gljId];
  54. if(subGlj){
  55. hintsArr.push(` ${subGlj.code} ${subGlj.name}${subGlj.specs ? '&nbsp;&nbsp;&nbsp;' + subGlj.specs : ''}&nbsp;&nbsp&nbsp;${subGlj.unit}&nbsp;&nbsp;&nbsp;${rationGlj.consumeAmt}`);
  56. }
  57. }
  58. hintsArr.push(`基价 元 ${ration.basePrice}`);
  59. if(ration.jobContent && ration.jobContent.toString().trim() !== ''){
  60. hintsArr.push(`工作内容:`);
  61. hintsArr = hintsArr.concat(ration.jobContent.split('\n'));
  62. }
  63. if(ration.annotation && ration.annotation.toString().trim() !== ''){
  64. hintsArr.push(`附注:`);
  65. hintsArr = hintsArr.concat(ration.annotation.split('\n'));
  66. }
  67. ration._doc.hint = hintsArr.join('<br>');
  68. }
  69. return rations;
  70. }
  71. };
  72. rationItemDAO.prototype.sortToNumber = function (datas) {
  73. for(let i = 0, len = datas.length; i < len; i++){
  74. let data = datas[i]._doc;
  75. if(_exist(data, 'labourPrice')){
  76. data['labourPrice'] = parseFloat(data['labourPrice']);
  77. }
  78. if(_exist(data, 'materialPrice')){
  79. data['materialPrice'] = parseFloat(data['materialPrice']);
  80. }
  81. if(_exist(data, 'machinePrice')){
  82. data['machinePrice'] = parseFloat(data['machinePrice']);
  83. }
  84. if(_exist(data, 'basePrice')){
  85. data['basePrice'] = parseFloat(data['basePrice']);
  86. }
  87. if(_exist(data, 'rationGljList')){
  88. for(let j = 0, jLen = data['rationGljList'].length; j < jLen; j++){
  89. let raGljObj = data['rationGljList'][j]._doc;
  90. if(_exist(raGljObj, 'consumeAmt')){
  91. raGljObj['consumeAmt'] = parseFloat(raGljObj['consumeAmt']);
  92. }
  93. }
  94. }
  95. }
  96. function _exist(data, attr){
  97. return data && data[attr] !== undefined && data[attr];
  98. }
  99. };
  100. rationItemDAO.prototype.getRationItemsBySection = function(rationRepId, sectionId,callback){
  101. let me = this;
  102. rationItemModel.find({"rationRepId": rationRepId, "sectionId": sectionId, "$or": [{"isDeleted": null}, {"isDeleted": false} ]},function(err,data){
  103. if(err) callback(true, "Fail to get items", "");
  104. else {
  105. me.sortToNumber(data);
  106. callback(false,"Get items successfully", data);
  107. }
  108. })
  109. };
  110. rationItemDAO.prototype.mixUpdateRationItems = function(rationLibId, lastOpr, sectionId, updateItems, addItems, rIds, callback){
  111. var me = this;
  112. if (updateItems.length == 0 && rIds.length == 0) {
  113. me.addRationItems(rationLibId, lastOpr, sectionId, addItems, callback);
  114. } else {
  115. me.removeRationItems(rationLibId, lastOpr, rIds, function(err, message, docs) {
  116. if (err) {
  117. callback(true, "Fail to remove", false);
  118. } else {
  119. me.updateRationItems(rationLibId, lastOpr, sectionId, updateItems, function(err, results){
  120. if (err) {
  121. callback(true, "Fail to save", false);
  122. } else {
  123. if (addItems && addItems.length > 0) {
  124. me.addRationItems(rationLibId, lastOpr, sectionId, addItems, callback);
  125. } else {
  126. callback(false, "Save successfully", results);
  127. }
  128. }
  129. });
  130. }
  131. })
  132. }
  133. };
  134. rationItemDAO.prototype.removeRationItems = function(rationLibId, lastOpr, rIds,callback){
  135. if (rIds.length > 0) {
  136. rationItemModel.collection.remove({ID: {$in: rIds}}, null, function(err, docs){
  137. if (err) {
  138. callback(true, "Fail to remove", false);
  139. } else {
  140. rationRepositoryDao.updateOprArr({ID: rationLibId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
  141. if(!err){
  142. callback(false, "Remove successfully", docs);
  143. }
  144. })
  145. }
  146. })
  147. } else {
  148. callback(false, "No records were deleted!", null);
  149. }
  150. };
  151. rationItemDAO.prototype.getRationItemsByCode = function(repId, code,callback){
  152. rationItemModel.find({"rationRepId": repId, "code": {'$regex': code, $options: '$i'}, "$or": [{"isDeleted": null}, {"isDeleted": false}]},function(err,data){
  153. if(err) callback(true, "Fail to get items", "")
  154. else callback(false,"Get items successfully", data);
  155. })
  156. };
  157. rationItemDAO.prototype.findRation = function (repId, keyword, callback) {
  158. var filter = {
  159. 'rationRepId': repId,
  160. '$and': [{
  161. '$or': [{'code': {'$regex': keyword, $options: '$i'}}, {'name': {'$regex': keyword, $options: '$i'}}]
  162. }, {
  163. '$or': [{'isDeleted': {"$exists":false}}, {'isDeleted': null}, {'isDeleted': false}]
  164. }]
  165. };
  166. rationItemModel.find(filter, function (err, data) {
  167. if (err) {
  168. callback(true, 'Fail to find ration', null);
  169. } else {
  170. callback(false, '', data);
  171. }
  172. })
  173. }
  174. rationItemDAO.prototype.getRationItem = function (repId, code, callback) {
  175. if (callback) {
  176. rationItemModel.findOne({rationRepId: repId, code: code, "$or": [{"isDeleted": null}, {"isDeleted": false}]}, '-_id').exec()
  177. .then(function (result, err) {
  178. if (err) {
  179. callback(1, '找不到定额“' + code +'”' , null);
  180. } else {
  181. callback(0, '', result);
  182. }
  183. });
  184. return null;
  185. } else {
  186. return rationItemModel.findOne({rationRepId: repId, code: code, "$or": [{"isDeleted": null}, {"isDeleted": false}]}, '-_id').exec();
  187. }
  188. };
  189. rationItemDAO.prototype.addRationItems = function(rationLibId, lastOpr, sectionId, items,callback){
  190. if (items && items.length > 0) {
  191. counter.counterDAO.getIDAfterCount(counter.moduleName.rations, items.length, function(err, result){
  192. var maxId = result.sequence_value;
  193. var arr = [];
  194. for (var i = 0; i < items.length; i++) {
  195. var obj = new rationItemModel(items[i]);
  196. obj.ID = (maxId - (items.length - 1) + i);
  197. obj.sectionId = sectionId;
  198. obj.rationRepId = rationLibId;
  199. arr.push(obj);
  200. }
  201. rationItemModel.collection.insert(arr, null, function(err, docs){
  202. if (err) {
  203. callback(true, "Fail to save", false);
  204. } else {
  205. rationRepositoryDao.updateOprArr({ID: rationLibId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
  206. if(err){
  207. callback(true, "Fail to sava operator", false);
  208. }
  209. else{
  210. callback(false, "Save successfully", docs);
  211. }
  212. })
  213. }
  214. })
  215. });
  216. } else {
  217. callback(true, "Source error!", false);
  218. }
  219. };
  220. rationItemDAO.prototype.updateRationItems = function(rationLibId, lastOpr, sectionId, items,callback){
  221. var functions = [];
  222. for (var i=0; i < items.length; i++) {
  223. functions.push((function(doc) {
  224. return function(cb) {
  225. var filter = {};
  226. if (doc.ID) {
  227. filter.ID = doc.ID;
  228. } else {
  229. filter.sectionId = sectionId;
  230. if (rationLibId) filter.rationRepId = rationLibId;
  231. filter.code = doc.code;
  232. }
  233. rationItemModel.update(filter, doc, cb);
  234. };
  235. })(items[i]));
  236. }
  237. functions.push((function () {
  238. return function (cb) {
  239. rationRepositoryDao.updateOprArr({ID: rationLibId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
  240. if(err){
  241. cb(err);
  242. }
  243. else{
  244. cb(null);
  245. }
  246. });
  247. }
  248. })());
  249. async.parallel(functions, function(err, results) {
  250. callback(err, results);
  251. });
  252. };
  253. //ration round func
  254. function round(v,e){
  255. var t=1;
  256. for(;e>0;t*=10,e--);
  257. for(;e<0;t/=10,e++);
  258. return Math.round(v*t)/t;
  259. }
  260. rationItemDAO.prototype.updateRationBasePrc = function (basePrcArr, callback) {
  261. async.each(basePrcArr, function (basePrcObj, finalCb) {
  262. let adjGljId = basePrcObj.gljId, adjBasePrice = basePrcObj.basePrice, adjGljType = basePrcObj.gljType;
  263. async.waterfall([
  264. function (cb) {
  265. if(typeof basePrcObj.delete !== 'undefined' && basePrcObj.delete === 1){
  266. rationItemModel.find({'rationGljList.gljId': adjGljId},{ID: 1, rationGljList: 1}, function (err, result) {
  267. if(err){
  268. cb(err);
  269. }
  270. else{
  271. //删除
  272. rationItemModel.update({'rationGljList.gljId': adjGljId}, {$pull: {rationGljList: {gljId: adjGljId}}}, {multi: true}, function (err) {
  273. if(err){
  274. cb(err);
  275. }
  276. else{
  277. //补充定额
  278. compleRationModel.find({'rationGljList.gljId': adjGljId},{ID: 1, rationGljList: 1}, function (err, compleRst) {
  279. if(err){
  280. cb(err);
  281. }
  282. else {
  283. compleRationModel.update({'rationGljList.gljId': adjGljId}, {$pull: {rationGljList: {gljId: adjGljId}}}, {multi: true}, function (err) {
  284. if(err){
  285. cb(err);
  286. }
  287. else {
  288. for(let i = 0, len = compleRst.length; i < len; i++){
  289. compleRst[i]._doc.type = 'complementary';
  290. }
  291. cb(null, result.concat(compleRst));
  292. }
  293. });
  294. }
  295. });
  296. }
  297. });
  298. }
  299. });
  300. }
  301. else{
  302. rationItemModel.find({'rationGljList.gljId': adjGljId}, {ID: 1, rationGljList: 1}, function (err, result) {
  303. if(err){
  304. cb(err);
  305. }
  306. else{
  307. compleRationModel.find({'rationGljList.gljId': adjGljId}, {ID: 1, rationGljList: 1}, function (err, compleRst) {
  308. if(err){
  309. cb(err);
  310. }
  311. else {
  312. for(let i = 0, len = compleRst.length; i < len; i++){
  313. compleRst[i]._doc.type = 'complementary';
  314. }
  315. cb(null, result.concat(compleRst));
  316. }
  317. });
  318. }
  319. });
  320. }
  321. },
  322. function (result, cb) {
  323. let compleRTasks = [], stdRTasks = [];
  324. //重算时需要用到的所有工料机,一次性取
  325. let compleGljIds = [], stdGljIds = [];
  326. for(let ration of result){
  327. for(let glj of ration.rationGljList){
  328. if(glj.type !== undefined && glj.type === 'complementary'){
  329. compleGljIds.push(glj.gljId);
  330. }
  331. else {
  332. stdGljIds.push(glj.gljId);
  333. }
  334. }
  335. }
  336. gljDao.getStdCompleGljItems(compleGljIds, stdGljIds, function (err, allGljs) {
  337. const processDecimal = -6;
  338. if(err){
  339. cb(err);
  340. }
  341. else {
  342. let gljIndex = {};
  343. for(let glj of allGljs){
  344. gljIndex[glj.ID] = glj;
  345. }
  346. async.each(result, function (rationItem, ecb) {
  347. let rationGljList = rationItem.rationGljList;
  348. let gljArr = [];
  349. for(let i=0; i<rationGljList.length; i++){
  350. let theGlj = gljIndex[rationGljList[i].gljId];
  351. if(theGlj !== undefined && theGlj){
  352. let gljParentType = -1;
  353. if(theGlj.ID === adjGljId){
  354. theGlj.gljType = adjGljType;
  355. }
  356. if(theGlj.gljType <= 3){
  357. gljParentType = theGlj.gljType;
  358. }
  359. if(theGlj.gljType > 200 && theGlj.gljType < 300){
  360. gljParentType = 2;
  361. }
  362. if(theGlj.gljType > 300 && theGlj.gljType < 400){
  363. gljParentType = 3;
  364. }
  365. //管理费
  366. if(theGlj.gljType === 6){
  367. gljParentType = 6;
  368. }
  369. //利润
  370. if(theGlj.gljType === 7){
  371. gljParentType = 7;
  372. }
  373. //风险费
  374. if(theGlj.gljType === 8){
  375. gljParentType = 8;
  376. }
  377. if(theGlj)
  378. if(theGlj.ID === adjGljId){
  379. gljArr.push({gljId: theGlj.ID, basePrice: adjBasePrice, gljParentType: gljParentType});
  380. }
  381. else {
  382. if(theGlj.priceProperty && Object.keys(theGlj.priceProperty).length > 0){
  383. let priceKeys = Object.keys(theGlj.priceProperty);
  384. gljArr.push({gljId: theGlj.ID, basePrice: parseFloat(theGlj.priceProperty[priceKeys[0]]), gljParentType: gljParentType});
  385. }
  386. else {
  387. gljArr.push({gljId: theGlj.ID, basePrice: parseFloat(theGlj.basePrice), gljParentType: gljParentType});
  388. }
  389. }
  390. }
  391. }
  392. gljArr.forEach(function (gljItem) {
  393. rationGljList.forEach(function (rationGlj) {
  394. if(gljItem.gljId === rationGlj.gljId){
  395. gljItem.consumeAmt = parseFloat(rationGlj.consumeAmt);
  396. }
  397. })
  398. });
  399. //recalculate the price of ration
  400. let labourPrc = [],
  401. materialPrc = [],
  402. machinePrc = [],
  403. managePrc = [],
  404. profitPrc = [],
  405. riskPrc = [],
  406. singlePrc,
  407. updatePrc = {labourPrice: 0, materialPrice: 0, machinePrice: 0, managePrice: 0, profitPrice: 0, riskPrice: 0, basePrice: 0};
  408. gljArr.forEach(function (gljItem) {
  409. if(gljItem.gljParentType !== -1){
  410. singlePrc = scMathUtil.roundTo(gljItem.basePrice * gljItem.consumeAmt, -3);
  411. if(gljItem.gljParentType === 1){
  412. labourPrc.push(singlePrc);
  413. }
  414. else if(gljItem.gljParentType ===2){
  415. materialPrc.push(singlePrc);
  416. }
  417. else if(gljItem.gljParentType === 3){
  418. machinePrc.push(singlePrc);
  419. }
  420. else if(gljItem.gljParentType === 6){
  421. managePrc.push(singlePrc);
  422. }
  423. else if(gljItem.gljParentType === 7){
  424. profitPrc.push(singlePrc);
  425. }
  426. else if(gljItem.gljParentType === 8){
  427. riskPrc.push(singlePrc);
  428. }
  429. }
  430. });
  431. if(labourPrc.length > 0){
  432. let sumLaP = 0;
  433. for(let i=0; i<labourPrc.length; i++){
  434. sumLaP = scMathUtil.roundTo(sumLaP + labourPrc[i], processDecimal);
  435. }
  436. updatePrc.labourPrice = scMathUtil.roundTo(sumLaP, -2);
  437. }
  438. if(materialPrc.length > 0){
  439. let sumMtP = 0;
  440. for(let i= 0; i<materialPrc.length; i++){
  441. sumMtP = scMathUtil.roundTo(sumMtP + materialPrc[i], processDecimal);
  442. }
  443. updatePrc.materialPrice = scMathUtil.roundTo(sumMtP, -2);
  444. }
  445. if(machinePrc.length > 0){
  446. let sumMaP = 0;
  447. for(let i =0; i< machinePrc.length; i++){
  448. sumMaP = scMathUtil.roundTo(sumMaP + machinePrc[i], processDecimal);
  449. }
  450. updatePrc.machinePrice = scMathUtil.roundTo(sumMaP, -2);
  451. }
  452. if(managePrc.length > 0){
  453. let sumMgP = 0;
  454. for(let i =0; i< managePrc.length; i++){
  455. sumMgP = scMathUtil.roundTo(sumMgP + managePrc[i], processDecimal);
  456. }
  457. updatePrc.managePrice = scMathUtil.roundTo(sumMgP, -2);
  458. }
  459. if(profitPrc.length > 0){
  460. let sumPfP = 0;
  461. for(let i =0; i< profitPrc.length; i++){
  462. sumPfP = scMathUtil.roundTo(sumPfP + profitPrc[i], processDecimal);
  463. }
  464. updatePrc.profitPrice = scMathUtil.roundTo(sumPfP, -2);
  465. }
  466. if(riskPrc.length > 0){
  467. let sumRkP = 0;
  468. for(let i =0; i< riskPrc.length; i++){
  469. sumRkP = scMathUtil.roundTo(sumRkP + riskPrc[i], processDecimal);
  470. }
  471. updatePrc.riskPrice = scMathUtil.roundTo(sumRkP, -2);
  472. }
  473. updatePrc.basePrice = scMathUtil.roundTo(
  474. updatePrc.labourPrice + updatePrc.materialPrice + updatePrc.machinePrice + updatePrc.managePrice + updatePrc.profitPrice + updatePrc.riskPrice, -2);
  475. let task = {
  476. updateOne: {
  477. filter: {
  478. ID: rationItem.ID
  479. },
  480. update: {
  481. labourPrice: updatePrc.labourPrice.toString(),
  482. materialPrice: updatePrc.materialPrice.toString(),
  483. machinePrice: updatePrc.machinePrice.toString(),
  484. basePrice: updatePrc.basePrice.toString()
  485. }
  486. }
  487. };
  488. //updateDataBase
  489. if(rationItem._doc.type !== undefined && rationItem._doc.type === 'complementary'){
  490. compleRTasks.push(task);
  491. ecb(null);
  492. }
  493. else {
  494. stdRTasks.push(task);
  495. ecb(null);
  496. }
  497. }, async function(err){
  498. if(err){
  499. cb(err);
  500. }
  501. else {
  502. //do sth
  503. try{
  504. if(compleRTasks.length > 0){
  505. await compleRationModel.bulkWrite(compleRTasks);
  506. }
  507. if(stdRTasks.length > 0){
  508. await rationItemModel.bulkWrite(stdRTasks);
  509. }
  510. }
  511. catch(e){
  512. cb(err);
  513. }
  514. cb(null);
  515. }
  516. });
  517. }
  518. });
  519. },
  520. ], function (err) {
  521. if(err){
  522. finalCb(err);
  523. }
  524. else{
  525. finalCb(null);
  526. }
  527. });
  528. }, function (err) {
  529. if(err){
  530. callback(err, 'Error');
  531. }
  532. else{
  533. callback(null, '');
  534. }
  535. });
  536. };
  537. rationItemDAO.prototype.getRationGljIds = function (data, callback) {
  538. let repId = data.repId;
  539. rationItemModel.find({rationRepId: repId}, function (err, result) {
  540. if(err){
  541. callback(err, 'Error', null);
  542. }
  543. else{
  544. let rstIds = [], newRst = [];
  545. result.forEach(function (data) {
  546. if(data.rationGljList.length >0){
  547. data.rationGljList.forEach(function (gljObj) {
  548. rstIds.push(gljObj.gljId);
  549. })
  550. }
  551. });
  552. for(let i= 0; i< rstIds.length; i++){
  553. if(newRst.indexOf(rstIds[i]) === -1){
  554. newRst.push(rstIds[i]);
  555. }
  556. }
  557. callback(null, '', newRst);
  558. }
  559. });
  560. };
  561. rationItemDAO.prototype.getRationsCodes = function (data, callback) {
  562. let repId = data.repId;
  563. rationItemModel.find({rationRepId: repId, isDeleted: false}, function (err, result) {
  564. if(err){
  565. callback(err, 'Error', null);
  566. }
  567. else{
  568. let rstCodes = [];
  569. result.forEach(function (rationItem) {
  570. rstCodes.push(rationItem.code);
  571. });
  572. callback(null, 'get all rationCodes success', rstCodes);
  573. }
  574. })
  575. };
  576. rationItemDAO.prototype.updateJobContent = function (lastOpr, repId, updateArr, callback) {
  577. rationRepositoryDao.updateOprArr({ID: repId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
  578. async.each(updateArr, function (obj, cb) {
  579. rationItemModel.update({rationRepId: repId, code: obj.code}, {$set: {jobContent: obj.jobContent}}, function (err) {
  580. if(err){
  581. cb(err);
  582. }
  583. else{
  584. cb(null);
  585. }
  586. })
  587. }, function (err) {
  588. if(err){
  589. callback(err);
  590. }
  591. else{
  592. callback(null);
  593. }
  594. });
  595. });
  596. }
  597. rationItemDAO.prototype.updateAnnotation = function (lastOpr, repId, updateArr, callback) {
  598. rationRepositoryDao.updateOprArr({ID: repId}, lastOpr, moment(Date.now()).format('YYYY-MM-DD HH:mm:ss'), function (err) {
  599. async.each(updateArr, function (obj, cb) {
  600. rationItemModel.update({rationRepId: repId, code: obj.code}, {$set: {annotation: obj.annotation}}, function (err) {
  601. if(err){
  602. cb(err);
  603. }
  604. else{
  605. cb(null);
  606. }
  607. })
  608. }, function (err) {
  609. if(err){
  610. callback(err);
  611. }
  612. else{
  613. callback(null);
  614. }
  615. });
  616. });
  617. };
  618. //计算导入数据的价格
  619. rationItemDAO.prototype.calcForRation = function (stdGljList, ration) {
  620. const processDecimal = -6;
  621. //根据工料机类型划分价格
  622. const labour = [1],
  623. material = [201, 202, 203, 204, 205, 206, 207],
  624. machine = [301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312],
  625. manage = [6],
  626. profit = [7],
  627. risk = [8];
  628. let labourPrc = [], materialPrc = [], machinePrc = [], managePrc = [], profitPrc = [], riskPrc = [],
  629. singlePrc, updatePrc = {labourPrice: 0, materialPrice: 0, machinePrice: 0, basePrice: 0, managePrice: 0, profitPrice: 0, riskPrice: 0};
  630. let rationGljList = ration.rationGljList;
  631. for(let rationGlj of rationGljList){
  632. let glj = stdGljList[rationGlj.gljId];
  633. let prcType = isDef(glj) ? getParentType(glj.gljType) : null;
  634. if(isDef(prcType)){
  635. singlePrc = scMathUtil.roundTo(parseFloat(glj.basePrice) * parseFloat(rationGlj.consumeAmt), -3);
  636. if(prcType === 'labour'){
  637. labourPrc.push(singlePrc);
  638. }
  639. else if(prcType === 'material'){
  640. materialPrc.push(singlePrc);
  641. }
  642. else if(prcType === 'machine'){
  643. machinePrc.push(singlePrc);
  644. }
  645. else if(prcType === 'manage'){
  646. managePrc.push(singlePrc);
  647. }
  648. else if(prcType === 'profit'){
  649. profitPrc.push(singlePrc);
  650. }
  651. else if(prcType === 'risk'){
  652. riskPrc.push(singlePrc);
  653. }
  654. }
  655. }
  656. //计算人工费
  657. if(labourPrc.length > 0){
  658. let sumLaP = 0;
  659. for(let i = 0, len = labourPrc.length; i < len; i++){
  660. sumLaP = scMathUtil.roundTo(sumLaP + labourPrc[i], processDecimal);
  661. }
  662. updatePrc.labourPrice = scMathUtil.roundTo(sumLaP, -2);
  663. }
  664. //材料费
  665. if(materialPrc.length > 0){
  666. let sumMtP = 0;
  667. for(let i = 0, len = materialPrc.length; i < len; i++){
  668. sumMtP = scMathUtil.roundTo(sumMtP + materialPrc[i], processDecimal);
  669. }
  670. updatePrc.materialPrice = scMathUtil.roundTo(sumMtP, -2);
  671. }
  672. //机械费
  673. if(machinePrc.length > 0){
  674. let sumMaP = 0;
  675. for(let i = 0, len = machinePrc.length; i < len; i++){
  676. sumMaP = scMathUtil.roundTo(sumMaP + machinePrc[i], processDecimal);
  677. }
  678. updatePrc.machinePrice = scMathUtil.roundTo(sumMaP, -2);
  679. }
  680. //管理费
  681. if(managePrc.length > 0){
  682. let sumMgP = 0;
  683. for(let i = 0, len = managePrc.length; i < len; i++){
  684. sumMgP = scMathUtil.roundTo(sumMgP + managePrc[i], processDecimal);
  685. }
  686. updatePrc.managePrice = scMathUtil.roundTo(sumMgP, -2);
  687. }
  688. //利润
  689. if(profitPrc.length > 0){
  690. let sumPfP = 0;
  691. for(let i = 0, len = profitPrc.length; i < len; i++){
  692. sumPfP = scMathUtil.roundTo(sumPfP + profitPrc[i], processDecimal);
  693. }
  694. updatePrc.profitPrice = scMathUtil.roundTo(sumPfP, -2);
  695. }
  696. //风险费
  697. if(riskPrc.length > 0){
  698. let sumRkP = 0;
  699. for(let i = 0, len = riskPrc.length; i < len; i++){
  700. sumRkP = scMathUtil.roundTo(sumRkP + riskPrc[i], processDecimal);
  701. }
  702. updatePrc.riskPrice = scMathUtil.roundTo(sumRkP, -2);
  703. }
  704. //基价
  705. updatePrc.basePrice = scMathUtil.roundTo(
  706. updatePrc.labourPrice + updatePrc.materialPrice + updatePrc.machinePrice + updatePrc.managePrice + updatePrc.profitPrice + updatePrc.riskPrice, -2);
  707. //更新定额数据
  708. ration.labourPrice = updatePrc.labourPrice.toString();
  709. ration.materialPrice = updatePrc.materialPrice.toString();
  710. ration.machinePrice = updatePrc.machinePrice.toString();
  711. ration.basePrice = updatePrc.basePrice.toString();
  712. function isDef(v){
  713. return v !== undefined && v !== null;
  714. }
  715. //是否属于人工、材料、机械类型
  716. function getParentType(type){
  717. if(labour.includes(type)){
  718. return 'labour';
  719. }
  720. if(material.includes(type)){
  721. return 'material';
  722. }
  723. if(machine.includes(type)){
  724. return 'machine';
  725. }
  726. if(manage.includes(type)){
  727. return 'manage';
  728. }
  729. if(profit.includes(type)){
  730. return 'profit';
  731. }
  732. if(risk.includes(type)){
  733. return 'risk'
  734. }
  735. return null;
  736. }
  737. };
  738. /**
  739. * 根据条件获取定额数据
  740. *
  741. * @param {Object} condition
  742. * @param {Object} fields
  743. * @param {String} indexBy
  744. * @return {Promise|Array}
  745. */
  746. rationItemDAO.prototype.getRationItemByCondition = async function (condition, fields = null, indexBy = null) {
  747. let result = [];
  748. if (Object.keys(condition).length <= 0) {
  749. return result;
  750. }
  751. result = await rationItemModel.find(condition, fields).sort({code: 1});
  752. if (indexBy !== null && result.length > 0) {
  753. let tmpResult = {};
  754. for(let tmp of result) {
  755. tmpResult[tmp[indexBy]] = tmp;
  756. }
  757. result = tmpResult;
  758. }
  759. return result;
  760. };
  761. /**
  762. * 从excel中批量新增数据
  763. *
  764. * @param {Number} rationRepId
  765. * @param {Array} data
  766. * @return {bool}
  767. */
  768. rationItemDAO.prototype.batchAddFromExcel = async function(rationRepId, data) {
  769. if (data.length <= 0) {
  770. return false;
  771. }
  772. // 获取定额库相关数据
  773. const rationRepository = await rationRepositoryDao.getRepositoryById(rationRepId);
  774. if (rationRepository.length !== 1 || rationRepository[0].gljLib === undefined) {
  775. return false;
  776. }
  777. // 获取标准工料机库数据
  778. const stdBillsLibListsModel = new STDGLJListModel();
  779. const stdGLJData = await stdBillsLibListsModel.getGljItemsByRepId(rationRepository[0].gljLib);
  780. // 整理标准工料机库数据
  781. let stdGLJList = {};
  782. let stdGLJListByID = {};
  783. for (const tmp of stdGLJData) {
  784. stdGLJList[tmp.code.toString()] = tmp.ID;
  785. stdGLJListByID[tmp.ID] = tmp;
  786. }
  787. let lastData = {};
  788. const rationData = [];
  789. // 编码列表,用于查找库中是否有对应数据
  790. let rationCodeList = [];
  791. let gljCodeList = [];
  792. // 插入失败的工料机列表(用于提示)
  793. this.failGLJList = [];
  794. for (const tmp of data) {
  795. if (tmp.length <= 0) {
  796. continue;
  797. }
  798. // 如果第一个字段为null则是工料机数据,放入上一个数据的工料机字段
  799. if (tmp[0] === undefined && Object.keys(lastData).length > 0) {
  800. // 如果不存在对应的工料机库数据则跳过
  801. if (stdGLJList[tmp[1]] === undefined) {
  802. const failString = '定额' + lastData.code + '下的' + tmp[1];
  803. this.failGLJList.push(failString);
  804. continue;
  805. }
  806. const tmpRationGlj = {
  807. gljId: stdGLJList[tmp[1]],
  808. consumeAmt: tmp[4],
  809. proportion: 0,
  810. };
  811. lastData.rationGljList.push(tmpRationGlj);
  812. if (gljCodeList.indexOf(tmp[1]) < 0) {
  813. gljCodeList.push(tmp[1]);
  814. }
  815. continue;
  816. }
  817. if (tmp[0] === '定额' && Object.keys(lastData).length > 0) {
  818. rationData.push(lastData);
  819. }
  820. // 组装数据
  821. lastData = {
  822. code: tmp[1],
  823. name: tmp[2],
  824. unit: tmp[3],
  825. caption: tmp[2],
  826. rationRepId: rationRepId,
  827. sectionId: 0,
  828. labourPrice: '0',
  829. materialPrice: '0',
  830. machinePrice: '0',
  831. basePrice: '0',
  832. rationGljList: []
  833. };
  834. // 防止重复加入
  835. if (rationCodeList.indexOf(tmp[1]) < 0) {
  836. rationCodeList.push(tmp[1]);
  837. }
  838. }
  839. // 最后一个入数组
  840. rationData.push(lastData);
  841. // 查找数据库中是否已存在待插入数据
  842. const condition = {
  843. rationRepId: rationRepId,
  844. code: { $in: rationCodeList }
  845. };
  846. const existCodeList = await this.getRationItemByCondition(condition, ['code'], 'code');
  847. // 过滤插入数据
  848. let insertData = [];
  849. //已存在定额,则更新价格及rationGLjList字段
  850. let updateData = [];
  851. for (const ration of rationData) {
  852. if (existCodeList[ration.code] !== undefined) {
  853. updateData.push(ration);
  854. continue;
  855. }
  856. insertData.push(ration);
  857. }
  858. //更新定额
  859. let updateBulk = [];
  860. for(let ration of updateData){
  861. this.calcForRation(stdGLJListByID, ration);
  862. updateBulk.push({
  863. updateOne: {
  864. filter: {rationRepId: rationRepId, code: ration.code},
  865. update: {$set: {rationGljList: ration.rationGljList, labourPrice: ration.labourPrice, materialPrice: ration.materialPrice,
  866. machinePrice: ration.machinePrice, basePrice: ration.basePrice}}
  867. }
  868. });
  869. }
  870. //更新数据库
  871. if(updateBulk.length > 0){
  872. await rationItemModel.bulkWrite(updateBulk);
  873. }
  874. // 如果都已经存在,直接返回
  875. if (insertData.length <= 0) {
  876. return true;
  877. }
  878. //计算价格
  879. for(let ration of insertData){
  880. this.calcForRation(stdGLJListByID, ration);
  881. }
  882. // 组织id
  883. const counterInfo = await counter.counterDAO.getIDAfterCount(counter.moduleName.rations, insertData.length);
  884. let maxId = counterInfo.sequence_value;
  885. maxId = parseInt(maxId);
  886. let count = 0;
  887. for (const index in insertData) {
  888. insertData[index].ID = maxId - (insertData.length - 1) + count;
  889. count++;
  890. }
  891. // 插入数据库
  892. const result = await rationItemModel.create(insertData);
  893. return result.length > 0;
  894. };
  895. /**
  896. * 导出到excel的数据
  897. *
  898. * @param {Number} rationRepId
  899. * @return {Array}
  900. */
  901. rationItemDAO.prototype.exportExcelData = async function(rationRepId) {
  902. const condition = {
  903. rationRepId: rationRepId
  904. };
  905. // @todo 限制导出的数量以防内存溢出
  906. const rationDataList = await this.getRationItemByCondition(condition, ['name', 'code', 'ID', 'sectionId', 'feeType', 'caption', 'basePrice']);
  907. // 整理数据
  908. let rationData = [];
  909. for (const tmp of rationDataList) {
  910. const sectionId = tmp.sectionId <= 0 || tmp.sectionId === undefined ? null : tmp.sectionId;
  911. const feeType = tmp.feeType === '' || tmp.feeType === undefined ? null : tmp.feeType;
  912. const ration = [sectionId, feeType, tmp.ID, tmp.code, tmp.name, tmp.caption, tmp.basePrice];
  913. rationData.push(ration);
  914. }
  915. //根据编号排序,优先级:number-number-..., number, Anumber....
  916. /*let regConnector = /-/g,
  917. regLetter = /[a-z,A-Z]/g,
  918. regNum = /\d+/g;
  919. rationData.sort(function (a, b) {
  920. let aCode = a[3],
  921. bCode = b[3],
  922. rst = 0;
  923. function compareConnector(arrA, arrB) {
  924. let lessArr = arrA.length <= arrB ? arrA : arrB;
  925. for (let i = 0; i < lessArr.length; i++) {
  926. let result = compareUnit(arrA[i], arrB[i]);
  927. if (result !== 0) {
  928. return result;
  929. } else {
  930. }
  931. }
  932. function compareUnit(uA, uB) {
  933. let uAV = parseFloat(uA),
  934. uBV = parseFloat(uB);
  935. if (uAV > uBV) {
  936. return 1;
  937. } else if (uAV < uBV) {
  938. return -1;
  939. }
  940. return 0;
  941. }
  942. }
  943. if (regConnector.test(a) && !regConnector.test(b)) {
  944. rst = -1;
  945. } else if (!regConnector.test(a) && regConnector.test(b)) {
  946. rst = 1;
  947. } else if (regConnector.test(a) && regConnector.test(b)) {
  948. }
  949. });
  950. rationData.sort(function (a, b) {
  951. let aCode = a[3],
  952. bCode = b[3],
  953. rst = 0,
  954. splitA = aCode.split('-'),
  955. splitB = bCode.split('-');
  956. if(splitA[0] > splitB[0]){
  957. rst = 1;
  958. }
  959. else if(splitA[0] < splitB[0]){
  960. rst = -1;
  961. }
  962. else {
  963. if(splitA[1] && splitB[1]){
  964. let floatA = parseFloat(splitA[1]),
  965. floatB = parseFloat(splitB[1]);
  966. if(floatA > floatB){
  967. rst = 1;
  968. }
  969. else if(floatA < floatB){
  970. rst = -1;
  971. }
  972. }
  973. }
  974. return rst;
  975. });*/
  976. const excelData = [['树ID', '取费专业', '定额ID', '定额编码', '定额名', '定额显示名称', '基价']];
  977. excelData.push.apply(excelData, rationData);
  978. return excelData;
  979. };
  980. /**
  981. * 批量更改章节id
  982. *
  983. * @param {Object} data
  984. * @return {bool}
  985. */
  986. rationItemDAO.prototype.batchUpdateSectionIdFromExcel = async function(data) {
  987. if (data.length <= 0) {
  988. return false;
  989. }
  990. // 批量执行update
  991. let bulkOprs = [];
  992. for (const tmp of data) {
  993. let rationId = parseInt(tmp[2]);
  994. rationId = isNaN(rationId) || rationId <= 0 ? 0 : rationId;
  995. let sectionId = parseInt(tmp[0]);
  996. sectionId = isNaN(sectionId) || sectionId <= 0 ? 0 : sectionId;
  997. // 取费专业
  998. let feeType = tmp[1] ? parseInt(tmp[1]) : null;
  999. feeType = isNaN(feeType) || feeType <= 0 ? null : feeType;
  1000. let name = tmp[4];
  1001. name = name ? name : '';
  1002. let caption = tmp[5];
  1003. caption = caption ? caption : '';
  1004. if (sectionId <= 0 || rationId <= 0) {
  1005. continue;
  1006. }
  1007. bulkOprs.push({updateOne: {filter: {ID: rationId}, update: {$set: {sectionId: sectionId, feeType: feeType, name: name, caption: caption}}}});
  1008. }
  1009. if(bulkOprs.length <= 0){
  1010. throw '无有效数据(树ID、定额ID不为空、且为数值)';
  1011. }
  1012. await rationItemModel.bulkWrite(bulkOprs);
  1013. };
  1014. module.exports = new rationItemDAO();