revise_bills.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Mai
  6. * @date
  7. * @version
  8. */
  9. const keyPre = 'revise_bills_maxLid:';
  10. const tidField = 'tender_id';
  11. const lidField = 'ledger_id';
  12. const pidField = 'ledger_pid';
  13. const pathField = 'full_path';
  14. module.exports = app => {
  15. class ReviseBills extends app.BaseService {
  16. /**
  17. * 构造函数
  18. *
  19. * @param {Object} ctx - egg全局变量
  20. * @return {void}
  21. */
  22. constructor(ctx) {
  23. super(ctx);
  24. this.tableName = 'revise_bills';
  25. }
  26. /**
  27. * 获取 修订 清单数据
  28. * @param {Number}tid - 标段id
  29. * @returns {Promise<void>}
  30. */
  31. async getData(tid) {
  32. return await this.db.select(this.tableName, {
  33. where: {tender_id: tid}
  34. });
  35. }
  36. /**
  37. * 获取节点数据
  38. * @param {Number} tid - 标段id
  39. * @param {Number} lid - 标段内,台账id
  40. * @returns {Promise<void>}
  41. */
  42. async getDataByLid (tid, lid) {
  43. return await this.db.get(this.tableName, {tender_id: tid, ledger_id: lid});
  44. }
  45. /**
  46. * 获取节点数据
  47. * @param id
  48. * @returns {Promise<Array>}
  49. */
  50. async getDataById(id) {
  51. if (id instanceof Array) {
  52. return await this.db.select(this.tableName, { where: {id: id} });
  53. } else {
  54. return await this.db.get(this.tableName, { id: id });
  55. }
  56. }
  57. /**
  58. * 获取最末的子节点
  59. * @param {Number} tenderId - 标段id
  60. * @param {Number} pid - 父节点id
  61. * @return {Object}
  62. */
  63. async getLastChildData(tid, pid) {
  64. this.initSqlBuilder();
  65. this.sqlBuilder.setAndWhere('tender_id', {
  66. value: tid,
  67. operate: '=',
  68. });
  69. this.sqlBuilder.setAndWhere('ledger_pid', {
  70. value: pid,
  71. operate: '=',
  72. });
  73. this.sqlBuilder.orderBy = [['order', 'DESC']];
  74. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  75. const resultData = await this.db.queryOne(sql, sqlParam);
  76. return resultData;
  77. }
  78. /**
  79. * 根据 父节点id 和 节点排序order 获取数据
  80. *
  81. * @param {Number} tid - 标段id
  82. * @param {Number} pid - 父节点id
  83. * @param {Number|Array} order - 排序
  84. * @return {Object|Array} - 查询结果
  85. */
  86. async getDataByParentAndOrder(tid, pid, order) {
  87. const result = await this.db.select(this.tableName, {where: {
  88. tender_id: tid, ledger_pid: pid, order: order
  89. }});
  90. return order instanceof Array ? result : (result.length > 0 ? result[0] : null);
  91. }
  92. /**
  93. * 根据 父节点ID 和 节点排序order 获取全部后节点数据
  94. * @param {Number} tid - 标段id
  95. * @param {Number} pid - 父节点id(ledger_pid)
  96. * @param {Number} order - 排序
  97. * @return {Array}
  98. */
  99. async getNextsData(tid, pid, order) {
  100. this.initSqlBuilder();
  101. this.sqlBuilder.setAndWhere('tender_id', {
  102. value: tid,
  103. operate: '=',
  104. });
  105. this.sqlBuilder.setAndWhere('ledger_pid', {
  106. value: pid,
  107. operate: '=',
  108. });
  109. this.sqlBuilder.setAndWhere('order', {
  110. value: order,
  111. operate: '>',
  112. });
  113. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
  114. const data = await this.db.query(sql, sqlParam);
  115. return data;
  116. }
  117. /**
  118. * 获取最大节点id
  119. *
  120. * @param {Number} tid - 台账id
  121. * @return {Number}
  122. * @private
  123. */
  124. async _getMaxLid(tid) {
  125. const cacheKey = keyPre + tid;
  126. let maxId = parseInt(await this.cache.get(cacheKey));
  127. if (!maxId) {
  128. const sql = 'SELECT Max(??) As max_id FROM ?? Where tender_id = ?';
  129. const sqlParam = ['ledger_id', this.tableName, tid];
  130. const queryResult = await this.db.queryOne(sql, sqlParam);
  131. maxId = queryResult.max_id || 0;
  132. this.cache.set(cacheKey, maxId, 'EX', this.ctx.app.config.cacheTime);
  133. }
  134. return maxId;
  135. }
  136. /**
  137. * 缓存最大节点id
  138. *
  139. * @param {Number} tid - 台账id
  140. * @param {Number} maxId - 当前最大节点id
  141. * @returns {Promise<void>}
  142. * @private
  143. */
  144. async _cacheMaxLid(tid, maxId) {
  145. this.cache.set(keyPre + tid , maxId, 'EX', this.ctx.app.config.cacheTime);
  146. }
  147. /**
  148. * 更新order
  149. * @param {Number} tid - 台账id
  150. * @param {Number} pid - 父节点id(ledger_id)
  151. * @param {Number} order - 开始更新的order
  152. * @param {Number} incre - 更新的增量
  153. * @returns {Promise<*>}
  154. * @private
  155. */
  156. async _updateChildrenOrder(tid, pid, order, incre = 1) {
  157. this.initSqlBuilder();
  158. this.sqlBuilder.setAndWhere('tender_id', {
  159. value: tid,
  160. operate: '=',
  161. });
  162. this.sqlBuilder.setAndWhere('order', {
  163. value: order,
  164. operate: '>=',
  165. });
  166. this.sqlBuilder.setAndWhere('ledger_pid', {
  167. value: pid,
  168. operate: '=',
  169. });
  170. this.sqlBuilder.setUpdateData('order', {
  171. value: Math.abs(incre),
  172. selfOperate: incre > 0 ? '+' : '-',
  173. });
  174. const [sql, sqlParam] = this.sqlBuilder.build(this.tableName, 'update');
  175. const data = await this.transaction.query(sql, sqlParam);
  176. return data;
  177. }
  178. /**
  179. * 新增数据(新增为selectData的后项,该方法不可单独使用)
  180. *
  181. * @param {Number} tid - 台账id
  182. * @param {uuid} rid - 修订id
  183. * @param {Object} select - 选中节点的数据
  184. * @param {Object} data - 新增节点的初始数据
  185. * @return {Object} - 新增结果
  186. * @private
  187. */
  188. async _addNodeData(tid, rid, select, data) {
  189. if (!data) {
  190. data = {};
  191. }
  192. const maxId = await this._getMaxLid(tid);
  193. data.id = this.uuid.v4();
  194. data.crid = rid;
  195. data.ledger_id = maxId + 1;
  196. data.ledger_pid = select.ledger_pid;
  197. data.tender_id = tid;
  198. data.level = select.level;
  199. data.order = select.order + 1;
  200. data.full_path = select.full_path.replace('.' + select.ledger_id, '.' + data.ledger_id);
  201. data.is_leaf = true;
  202. const result = await this.transaction.insert(this.tableName, data);
  203. this._cacheMaxLid(tid, maxId + 1);
  204. return result;
  205. }
  206. /**
  207. * 新增节点
  208. * @param {Number} tid - 台账id
  209. * @param {uuid} rid - 修订id
  210. * @param {Number} lid - 清单节点id
  211. * @returns {Promise<void>}
  212. */
  213. async addNode(tid, rid, lid) {
  214. if (!tid || !rid || !lid) return null;
  215. const select = await this.getDataByLid(tid, lid);
  216. if (!select) {
  217. throw '新增节点数据错误';
  218. }
  219. this.transaction = await this.db.beginTransaction();
  220. try {
  221. await this._updateChildrenOrder(tid, select.ledger_pid, select.order+1);
  222. const newNode = await this._addNodeData(tid, rid, select);
  223. if (newNode.affectedRows !== 1) {
  224. throw '新增节点数据额错误';
  225. }
  226. await this.transaction.commit();
  227. this.transaction = null;
  228. } catch (err) {
  229. await this.transaction.rollback();
  230. this.transaction = null;
  231. throw err;
  232. }
  233. const createData = await this.getDataByParentAndOrder(tid, select.ledger_pid, [select.order + 1]);
  234. const updateData = await this.getNextsData(tid, select.ledger_pid, select.order + 1);
  235. return {create: createData, update: updateData};
  236. }
  237. /**
  238. * 上移节点
  239. *
  240. * @param {Number} tid - 台账id
  241. * @param {Number} lid - 选中节点id
  242. * @return {Array} - 发生改变的数据
  243. */
  244. async upMoveNode(tid, lid) {
  245. if (!tid || !lid) return null;
  246. const select = await this.getDataByLid(tid, lid);
  247. if (!select) {
  248. throw '上移节点数据错误';
  249. }
  250. const pre = await this.getDataByParentAndOrder(tid, select.ledger_pid, select.order - 1);
  251. if (!pre) {
  252. throw '节点不可上移';
  253. }
  254. this.transaction = await this.db.beginTransaction();
  255. try {
  256. const sData = await this.transaction.update(this.tableName, { id: select.id, order: select.order - 1 });
  257. const pData = await this.transaction.update(this.tableName, { id: pre.id, order: pre.order + 1 });
  258. await this.transaction.commit();
  259. } catch (err) {
  260. await this.transaction.rollback();
  261. throw err;
  262. }
  263. const resultData = await this.getDataByParentAndOrder(tid, select.ledger_pid, [select.order, pre.order]);
  264. return { update: resultData };
  265. }
  266. /**
  267. * 下移节点
  268. *
  269. * @param {Number} tid - 台账id
  270. * @param {Number} lid - 选中节点id
  271. * @return {Array} - 发生改变的数据
  272. */
  273. async downMoveNode(tid, lid) {
  274. if (!tid || !lid) return null;
  275. const select = await this.getDataByLid(tid, lid);
  276. if (!select) {
  277. throw '下移节点数据错误';
  278. }
  279. const next = await this.getDataByParentAndOrder(tid, select.ledger_pid, select.order + 1);
  280. if (!next) {
  281. throw '节点不可下移';
  282. }
  283. this.transaction = await this.db.beginTransaction();
  284. try {
  285. const sData = await this.transaction.update(this.tableName, { id: select.id, order: select.order + 1 });
  286. const pData = await this.transaction.update(this.tableName, { id: next.id, order: next.order - 1 });
  287. await this.transaction.commit();
  288. } catch (err) {
  289. await this.transaction.rollback();
  290. throw err;
  291. }
  292. const resultData = await this.getDataByParentAndOrder(tid, select.ledger_pid, [select.order, next.order]);
  293. return { update: resultData };
  294. }
  295. /**
  296. * 批量插入子项
  297. * @param {uuid} rid - 修订id
  298. * @param {Number} lid - 节点id
  299. * @param {Object} data - 批量插入数据
  300. * @return {Promise<void>}
  301. */
  302. async batchInsertChild(tid, rid, lid, data) {
  303. const result = { ledger: {}, pos: null };
  304. if (!tid || !rid || !lid) return result;
  305. const select = await this.getDataByLid(tid, lid);
  306. if (!select) {
  307. throw '位置数据错误';
  308. }
  309. // 计算id和order
  310. const maxId = await this._getMaxLid(tid);
  311. const lastChild = await this.getLastChildData(tid, lid);
  312. const order = lastChild ? lastChild.order : 0;
  313. // 整理数据
  314. const bills = [], pos = [], newIds = [];
  315. for (let i = 0, iLen = data.length; i < iLen; i++) {
  316. // 合并新增数据
  317. const qd = {
  318. crid: rid,
  319. id: this.uuid.v4(),
  320. tender_id: tid,
  321. ledger_id: maxId + i + 1,
  322. ledger_pid: select.ledger_id,
  323. is_leaf: true,
  324. order: order + i + 1,
  325. level: select.level + 1,
  326. b_code: data[i].b_code,
  327. name: data[i].name,
  328. unit: data[i].unit,
  329. unit_price: data[i].price,
  330. };
  331. const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
  332. qd.sgfh_qty = 0;
  333. for (const p of data[i].pos) {
  334. const inP = {
  335. id: this.uuid.v4(), tid: tid, lid: qd.id, crid: rid,
  336. add_stage: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
  337. name: p.name, drawing_code: p.drawing_code,
  338. };
  339. if (p.quantity) {
  340. inP.sgfh_qty = this.round(p.quantity, precision.value);
  341. inP.quantity = inP.sgfh_qty;
  342. }
  343. qd.sgfh_qty = this.ctx.helper.add(qd.sgfh_qty, inP.sgfh_qty);
  344. pos.push(inP);
  345. }
  346. qd.full_path = select.full_path + '.' + qd.ledger_id;
  347. qd.sgfh_tp = this.ctx.helper.mul(qd.sgfh_qty, qd.unit_price, this.ctx.tender.info.decimal.tp);
  348. qd.quantity = qd.sgfh_qty;
  349. qd.total_price = qd.sgfh_tp;
  350. bills.push(qd);
  351. newIds.push(qd.id);
  352. }
  353. this.transaction = await this.db.beginTransaction();
  354. try {
  355. // 更新父项isLeaf
  356. if (!lastChild) {
  357. await this.transaction.update(this.tableName, {
  358. is_leaf: false,
  359. unit_price: null,
  360. quantity: null,
  361. total_price: null,
  362. deal_qty: null,
  363. deal_tp: null,
  364. }, {tender_id: rid, id: select.id});
  365. }
  366. // 数据库创建新增节点数据
  367. await this.transaction.insert(this.tableName, bills);
  368. await this.transaction.insert(this.ctx.service.revisePos.tableName, pos);
  369. this._cacheMaxLid(tid, maxId + data.length);
  370. await this.transaction.commit();
  371. } catch (err) {
  372. await this.transaction.rollback();
  373. throw err;
  374. }
  375. // 查询应返回的结果
  376. result.ledger.create = await this.getDataById(newIds);
  377. if (!lastChild) {
  378. result.ledger.update = await this.getDataByLid(select.id);
  379. }
  380. result.pos = await this.ctx.service.revisePos.getDataByLid(tid, newIds);
  381. return result;
  382. }
  383. /**
  384. * 批量插入后项
  385. * @param {Number} tid - 台账id
  386. * @param {uuid} rid - 修订id
  387. * @param {Number} lid - 节点id
  388. * @param {Object} data - 批量插入数据
  389. * @return {Promise<void>}
  390. */
  391. async batchInsertNext(tid, rid, lid, data) {
  392. const result = { ledger: {}, pos: null };
  393. if (!tid || !rid || !lid) return result;
  394. const select = await this.getDataByLid(tid, lid);
  395. if (!select) {
  396. throw '位置数据错误';
  397. }
  398. const parentData = await this.getDataByLid(tid, select.ledger_pid);
  399. if (!parentData) {
  400. throw '位置数据错误';
  401. }
  402. // 计算id和order
  403. const maxId = await this._getMaxLid(tid);
  404. const order = select.order;
  405. // 整理数据
  406. const bills = [], pos = [], newIds = [];
  407. for (let i = 0, iLen = data.length; i < iLen; i++) {
  408. // 合并新增数据
  409. const qd = {
  410. crid: rid,
  411. id: this.uuid.v4(),
  412. tender_id: tid,
  413. ledger_id: maxId + i + 1,
  414. ledger_pid: parentData.ledger_id,
  415. is_leaf: true,
  416. order: order + i + 1,
  417. level: parentData.level + 1,
  418. b_code: data[i].b_code,
  419. name: data[i].name,
  420. unit: data[i].unit,
  421. unit_price: data[i].price,
  422. };
  423. const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
  424. qd.sgfh_qty = 0;
  425. for (const p of data[i].pos) {
  426. const inP = {
  427. id: this.uuid.v4(), tid: tid, lid: qd.id, crid: rid,
  428. add_stage: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
  429. name: p.name, drawing_code: p.drawing_code,
  430. };
  431. if (p.quantity) {
  432. inP.sgfh_qty = this.round(p.quantity, precision.value);
  433. inP.quantity = inP.sgfh_qty;
  434. }
  435. qd.sgfh_qty = this.ctx.helper.add(qd.sgfh_qty, inP.sgfh_qty);
  436. pos.push(inP);
  437. }
  438. qd.full_path = parentData.full_path + '.' + qd.ledger_id;
  439. qd.sgfh_tp = this.ctx.helper.mul(qd.sgfh_qty, qd.unit_price, this.ctx.tender.info.decimal.tp);
  440. qd.quantity = qd.sgfh_qty;
  441. qd.total_price = qd.sgfh_tp;
  442. bills.push(qd);
  443. newIds.push(qd.id);
  444. }
  445. this.transaction = await this.db.beginTransaction();
  446. try {
  447. // 选中节点的所有后兄弟节点,order+粘贴节点个数
  448. await this._updateChildrenOrder(tid, select.ledger_pid, select.order+1);
  449. // 数据库创建新增节点数据
  450. await this.transaction.insert(this.tableName, bills);
  451. await this.transaction.insert(this.ctx.service.revisePos.tableName, pos);
  452. this._cacheMaxLid(tid, maxId + data.length);
  453. await this.transaction.commit();
  454. } catch (err) {
  455. await this.transaction.rollback();
  456. throw err;
  457. }
  458. // 查询应返回的结果
  459. result.ledger.create = await this.getDataById(newIds);
  460. result.ledger.update = await this.getNextsData(select.tender_id, select.ledger_pid, select.order + data.length);
  461. result.pos = await this.ctx.service.revisePos.getDataByLid(tid, newIds);
  462. return result;
  463. }
  464. }
  465. return ReviseBills;
  466. };