phase_pay_detail.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. 'use strict';
  2. /**
  3. *
  4. *
  5. * @author Mai
  6. * @date
  7. * @version
  8. */
  9. const payType = {
  10. bqsf: 'bqsf', bqyf: 'bqyf', gcjl: 'gcjl', qtfk: 'qtfk', qtkk: 'qtkk'
  11. };
  12. const defaultPays = [
  13. { tree_id: 1, tree_pid: -1, tree_level: 1, tree_order: 1, tree_is_leaf: 1, tree_full_path: '1', pay_type: 'bqyf', is_minus: 0, is_fixed: 1, name: '本期应付' },
  14. { tree_id: 2, tree_pid: -1, tree_level: 1, tree_order: 2, tree_is_leaf: 1, tree_full_path: '2', pay_type: 'bqsf', is_minus: 0, is_fixed: 1, name: '本期实付' },
  15. { tree_id: 3, tree_pid: -1, tree_level: 1, tree_order: 3, tree_is_leaf: 0, tree_full_path: '3', pay_type: 'gcjl', is_minus: 0, is_fixed: 1, name: '工程计量款' },
  16. { tree_id: 4, tree_pid: -1, tree_level: 1, tree_order: 4, tree_is_leaf: 0, tree_full_path: '4', pay_type: 'qtfk', is_minus: 0, is_fixed: 1, name: '其他付款项' },
  17. { tree_id: 5, tree_pid: -1, tree_level: 1, tree_order: 5, tree_is_leaf: 0, tree_full_path: '5', pay_type: 'qtkk', is_minus: 1, is_fixed: 1, name: '其他扣款项' },
  18. { tree_id: 6, tree_pid: 3, tree_level: 2, tree_order: 1, tree_is_leaf: 1, tree_full_path: '3-6', pay_type: '', is_minus: 0, is_fixed: 0, name: '本期完成计量', expr: 'bqwc' },
  19. { tree_id: 7, tree_pid: 4, tree_level: 2, tree_order: 1, tree_is_leaf: 1, tree_full_path: '4-7', pay_type: '', is_minus: 0, is_fixed: 0, name: '新增付款项' },
  20. { tree_id: 8, tree_pid: 5, tree_level: 2, tree_order: 1, tree_is_leaf: 1, tree_full_path: '5-8', pay_type: '', is_minus: 1, is_fixed: 0, name: '新增扣款项' },
  21. ];
  22. const TreeService = require('../base/base_tree_service');
  23. const Ledger = require('../lib/ledger');
  24. const deallineType = {
  25. phaseCount: 'phaseCount',
  26. stageCount: 'stageCount',
  27. gather: 'gather',
  28. contract: 'contract',
  29. };
  30. const math = require('mathjs');
  31. math.config({
  32. number: 'BigNumber',
  33. });
  34. const validField = ['name', 'is_pause', 'is_gather', 'start_tp', 'start_expr', 'range_tp', 'range_expr', 'tp', 'expr', 'postil', 'dl_type', 'dl_value'];
  35. const infoField = ['name', 'postil'];
  36. const calcField = validField.filter(x => { return infoField.indexOf(x) < 0; });
  37. class PayCalculator {
  38. constructor (ctx, phasePay) {
  39. this.ctx = ctx;
  40. this.phasePay = phasePay;
  41. this.percentReg = /((\d+)|((\d+)(\.\d+)))%/g;
  42. this.tenderInfo = ctx.tender.info;
  43. this.decimal = this.tenderInfo.decimal.pay ? this.tenderInfo.decimal.payTp : this.tenderInfo.decimal.tp;
  44. this.orderReg = /f\d+/ig;
  45. this.nodeReg = /<<[a-z0-9\-]+>>/ig;
  46. /* 以下变量在调用calculate方法后获得
  47. this.add;
  48. this.pre;
  49. this.cur;
  50. this.yf;
  51. */
  52. }
  53. /**
  54. * 获取 计算基数
  55. * @returns {Promise<void>}
  56. */
  57. getCalcBase () {
  58. if (this.bases) return;
  59. const bases = this.ctx.service.phasePay.getPhasePayCalcBase(this.phasePay, this.tenderInfo);
  60. this.bases = bases.sort(function (a, b) {
  61. return a.sort - b.sort;
  62. });
  63. for (const b of this.bases) {
  64. b.reg = new RegExp(b.code, 'igm');
  65. }
  66. }
  67. getCalcAdd() {
  68. if (this.addBase) return;
  69. const calc_base = this.phasePay.calc_base;
  70. this.addBase = {
  71. contract_tp: this.ctx.helper.add(calc_base.contract_tp, calc_base.pre_contract_tp),
  72. qc_tp: this.ctx.helper.add(calc_base.qc_tp, calc_base.pre_qc_tp),
  73. gather_tp: this.ctx.helper.add(calc_base.gather_tp, calc_base.pre_gather_tp),
  74. };
  75. }
  76. _calculateTpExpr(pay, pays) {
  77. let formula = pay.expr;
  78. const nodeParam = pay.expr.match(this.nodeReg);
  79. if (nodeParam) {
  80. for (const op of nodeParam) {
  81. const id = op.substring(2, op.length - 2);
  82. const payNode = pays.find(x => { return x.uuid === id; });
  83. formula = formula.replace(op, payNode ? payNode.tp || 0 : 0);
  84. }
  85. }
  86. for (const b of this.bases) {
  87. const value = b.checkStart && (!pay.pre_used && pay.start_tp)
  88. ? this.ctx.helper.sub(this.addBase[pay.checkStart], pay.start_tp)
  89. : b.value;
  90. formula = formula.replace(b.reg, value);
  91. }
  92. const percent = formula.match(this.percentReg);
  93. if (percent) {
  94. for (const p of percent) {
  95. const v = math.eval(p.replace(new RegExp('%', 'gm'), '/100'));
  96. formula = formula.replace(p, v);
  97. }
  98. }
  99. try {
  100. // 使用mathjs计算 math.eval('17259401.95*0.9') = 15533461.754999999,正确应为 15533461.755
  101. // const value = math.eval(formula);
  102. // 使用逆波兰法四则运算,可防止出现误差,但是只支持四则运算,不支持科学运算
  103. // const value = this.ctx.helper.calcExprStrRpn(formula);
  104. // 使用mathjs的大数运算,可支持所有
  105. const value = parseFloat(math.eval(formula));
  106. return Number.isFinite(value) ? value : 0;
  107. } catch(err) {
  108. return 0;
  109. }
  110. }
  111. _calculateExpr(expr) {
  112. let formula = expr;
  113. for (const b of this.bases) {
  114. formula = formula.replace(b.reg, b.value ? b.value : 0);
  115. }
  116. const percent = formula.match(this.percentReg);
  117. if (percent) {
  118. for (const p of percent) {
  119. const v = math.eval(p.replace(new RegExp('%', 'gm'), '/100'));
  120. formula = formula.replace(p, v);
  121. }
  122. }
  123. try {
  124. // 使用mathjs计算 math.eval('17259401.95*0.9') = 15533461.754999999,正确应为 15533461.755
  125. // const value = math.eval(formula);
  126. // 使用逆波兰法四则运算,可防止出现误差,但是只支持四则运算,不支持科学运算
  127. // const value = this.ctx.helper.calcExprStrRpn(formula);
  128. // 使用mathjs的大数运算,可支持所有
  129. const value = parseFloat(math.eval(formula));
  130. return Number.isFinite(value) ? value : 0;
  131. } catch(err) {
  132. return 0;
  133. }
  134. }
  135. /**
  136. * 计算起扣金额、付(扣)款限额
  137. *
  138. * @param {Array} pays - (标段)合同支付数据
  139. */
  140. calculateStartRangePrice (payTree) {
  141. for (const p of payTree.nodes) {
  142. // 上一期已计量的合同支付项,不予计算起扣金额、扣款限额
  143. if (p.pre_used) continue;
  144. if (p.start_expr) {
  145. p.start_tp = this.ctx.helper.round(this._calculateExpr(p.start_expr), this.decimal);
  146. } else if (p.start_tp && !p.start_expr) {
  147. p.start_tp = this.ctx.helper.round(p.start_tp, this.decimal);
  148. }
  149. if (p.range_expr) {
  150. p.range_price = this.ctx.helper.round(this._calculateExpr(p.range_expr), this.decimal);
  151. } else if (p.range_price && !p.range_expr) {
  152. p.range_price = this.ctx.helper.round(p.range_price, this.decimal);
  153. }
  154. }
  155. }
  156. /**
  157. * 检查是否到达 计提期限
  158. * @param pay
  159. */
  160. _checkDeadline(pay) {
  161. switch (pay.dl_type) {
  162. case deallineType.phaseCount:
  163. return this.phasePay.phase_order >= pay.dl_value;
  164. case deallineType.stageCount:
  165. const maxStageOrder = this.ctx.helper._.max(this.phasePay.rela_stage.map(x => { return x.stage_order; }));
  166. return maxStageOrder >= pay.dl_value;
  167. case deallineType.gather:
  168. case deallineType.contract:
  169. const deallineTp = this.add[pay.dl_type + '_tp'];
  170. return deallineTp >= pay.dl_value;
  171. default :
  172. return false;
  173. }
  174. }
  175. getLeafOrder(data, pays, parentId) {
  176. if (!data || !data.expr) return [];
  177. const nodeParam = data.expr.match(this.nodeReg);
  178. if (!nodeParam || nodeParam.length === 0) return [];
  179. const result = [...nodeParam];
  180. for (const op of nodeParam) {
  181. const id = op.substring(2, op.length - 2);
  182. if (id === data.uuid || id === parentId) {
  183. result.push(op);
  184. } else {
  185. const subPay = pays.find(x => { return x.uuid === id; });
  186. const sub = this.getLeafOrder(subPay, pays, data.uuid);
  187. if (sub.length > 0) {
  188. result.push(...sub);
  189. } else {
  190. result.push(op);
  191. }
  192. }
  193. }
  194. return this.ctx.helper._.uniq(result);
  195. }
  196. sortPaysByCalc(payTree) {
  197. const calcArr = [];
  198. for (const pay of payTree.nodes) {
  199. if (pay.pay_type === payType.bqyf) {
  200. pay.calcSort = 3;
  201. } else if (pay.pay_type === payType.bqsf) {
  202. pay.calcSort = 4;
  203. } else if (pay.children && pay.children.length > 0) {
  204. pay.calcSort = 2;
  205. } else {
  206. pay.calcSort = 1;
  207. pay.calcLeaf = this.getLeafOrder(pay, payTree.nodes);
  208. }
  209. calcArr.push(pay);
  210. }
  211. calcArr.sort((x, y) => {
  212. const calcSort = x.calcSort - y.calcSort;
  213. if (calcSort) return calcSort;
  214. if (x.calcSort === 2) return -(x.tree_level - y.tree_level);
  215. return x.calcLeaf.length - y.calcLeaf.length;
  216. });
  217. return calcArr;
  218. }
  219. _calculateYf(yf, pays) {
  220. yf.tp = 0;
  221. for (const p of pays) {
  222. if (p.payType || !p.is_gather || !p.tree_is_leaf) continue;
  223. yf.tp = !p.is_minus ? this.ctx.helper.add(yf.tp, p.tp) : this.ctx.helper.sub(yf.tp, p.tp);
  224. }
  225. const bqyf = this.bases.find(function (x) {return x.code === 'bqyf'});
  226. if (bqyf) bqyf.value = yf.tp;
  227. }
  228. _calculateSf(sf, pays) {
  229. if (sf.expr) {
  230. sf.tp = this.ctx.helper.round(this._calculateExpr(sf, pays), this.decimal);
  231. } else {
  232. const yf = pays.find(x => { return x.pay_type === payType.bqyf; });
  233. sf.tp = yf.tp;
  234. }
  235. sf.tp = sf.range_tp ? Math.min(this.ctx.helper.sub(sf.range_tp, sf.pre_tp), sf.tp) : sf.tp;
  236. }
  237. _calculateGather(pay) {
  238. pay.tp = 0;
  239. for (const c of pay.children) {
  240. if (c.children && c.children.length > 0) this._calculateGather(c);
  241. if (!c.is_gather) continue;
  242. pay.tp = this.ctx.helper.add(pay.tp, c.tp);
  243. }
  244. }
  245. _calculateCommon(pay, pays) {
  246. // 暂停计量|未达起扣金额时,不计算
  247. if (pay.is_pause || (pay.start_tp && this.addBase.gather_tp < pay.start_tp)) {
  248. pay.tp = 0;
  249. return;
  250. }
  251. if (this._checkDeadline(pay)) {
  252. pay.tp = this.ctx.helper.sub(pay.range_tp, pay.pre_tp);
  253. } else if (pay.expr) {
  254. pay.tp = this.ctx.helper.round(this._calculateTpExpr(pay, pays), this.decimal);
  255. } else {
  256. pay.tp = this.ctx.helper.round(pay.tp || 0, this.decimal);
  257. }
  258. pay.tp = pay.range_tp ? Math.min(this.ctx.helper.sub(pay.range_tp, pay.pre_tp), pay.tp) : pay.tp;
  259. }
  260. /**
  261. * 计算本期、截止本期金额
  262. * @param {Array} pays - (标段&期)合同支付数据
  263. */
  264. calculate(pays) {
  265. for (const p of pays) {
  266. switch (p.pay_type) {
  267. case payType.bqyf:
  268. this._calculateYf(p, pays); break;
  269. case payType.bqsf:
  270. this._calculateSf(p, pays); break;
  271. case payType.gcjl:
  272. case payType.qtfk:
  273. case payType.qtkk:
  274. this._calculateGather(p); break;
  275. default:
  276. this._calculateCommon(p, pays); break;
  277. }
  278. p.end_tp = this.ctx.helper.add(p.pre_tp, p.tp);
  279. }
  280. }
  281. calculateAll(payTree) {
  282. payTree.nodes.forEach(x => {
  283. x.org_tp = x.tp || 0;
  284. x.org_start_tp = x.start_tp || 0;
  285. x.org_range_tp = x.range_tp || 0;
  286. });
  287. this.getCalcBase();
  288. this.getCalcAdd();
  289. this.calculateStartRangePrice(payTree);
  290. const calcPays = this.sortPaysByCalc(payTree);
  291. this.calculate(calcPays);
  292. payTree.nodes.forEach(p => {
  293. p.calcUpdate = !this.ctx.helper.numEqual(p.org_tp, p.tp) || !this.ctx.helper.numEqual(p.org_start_tp, p.start_tp) || !this.ctx.helper.numEqual(p.org_range_tp, p.range_tp);
  294. });
  295. }
  296. }
  297. class PhasePayDetail extends TreeService {
  298. /**
  299. * 构造函数
  300. *
  301. * @param {Object} ctx - egg全局变量
  302. * @param {String} tableName - 表名
  303. * @return {void}
  304. */
  305. constructor(ctx, setting) {
  306. super(ctx, {
  307. mid: 'master_id',
  308. kid: 'tree_id',
  309. pid: 'tree_pid',
  310. order: 'tree_order',
  311. level: 'tree_level',
  312. isLeaf: 'tree_is_leaf',
  313. fullPath: 'tree_full_path',
  314. keyPre: '',
  315. uuid: true,
  316. });
  317. this.tableName = 'phase_pay_detail';
  318. }
  319. getMasterKey(phasePay) {
  320. return phasePay.curTimes
  321. ? `${phasePay.id}-${phasePay.curTimes}-${phasePay.curOrder}`
  322. : `${phasePay.id}-${phasePay.audit_times}-${phasePay.audit_max_sort}`;
  323. }
  324. async initPhaseDataEmpty(conn, phasePay) {
  325. const user_id = this.ctx.session.sessionUser.accountId;
  326. const insertData = [];
  327. for (const dp of defaultPays) {
  328. insertData.push({
  329. tid: phasePay.tid, phase_id: phasePay.id, create_user_id: user_id, update_user_id: user_id,
  330. uuid: this.uuid.v4(), ...dp,
  331. });
  332. }
  333. await conn.insert(this.tableName, insertData);
  334. }
  335. async initPhaseDataByPre(conn, phasePay, prePhase) {
  336. const preData = await this.getAllDataByCondition({
  337. where: { phase_id: prePhase.id, audit_times: prePhase.audit_times, audit_sort: audit_max_sort },
  338. });
  339. for (const pd of preData) {
  340. delete pd.id;
  341. pd.audit_times = 1;
  342. pd.audit_sort = 0;
  343. }
  344. await conn.insert(this.tableName, preData);
  345. }
  346. async initPhaseDataByAudit(conn, phasePay, newTimes, newSort) {
  347. const preData = await this.getDetailData(phasePay);
  348. for (const pd of preData) {
  349. delete pd.id;
  350. pd.master_id = `${phasePay.id}-${newTimes}-${newSort}`;
  351. pd.audit_times = newTimes;
  352. pd.audit_sort = newSort;
  353. }
  354. await conn.insert(this.tableName, preData);
  355. }
  356. async initPhaseData(conn, phasePay){
  357. if (!conn) throw '内部错误';
  358. const prePhase = await this.ctx.service.phasePay.getPhasePayByOrder(phasePay.tid, phasePay.phase_order - 1);
  359. if (prePhase) {
  360. await this.initPhaseDataByPre(conn, phasePay, prePhase);
  361. } else {
  362. await this.initPhaseDataEmpty(conn, phasePay);
  363. }
  364. }
  365. async getDetailData(phasePay) {
  366. return await this.getAllDataByCondition({ where: { master_id: this.getMasterKey(phasePay)} });
  367. }
  368. calculate(phasePay, details) {
  369. const payTree = new Ledger.baseTree(this.ctx, {
  370. id: 'tree_id', pid: 'tree_pid', order: 'tree_order',
  371. level: 'tree_level', isLeaf: 'tree_is_leaf', fullPath: 'tree_full_path',
  372. rootId: -1, calcField: [],
  373. });
  374. payTree.loadDatas(details);
  375. const payCalculator = new PayCalculator(this.ctx, phasePay);
  376. payCalculator.calculateAll(payTree);
  377. return payTree.getDefaultDatas();
  378. }
  379. async calculateSave(phasePay, transaction) {
  380. const details = await this.getDetailData(phasePay);
  381. if (details.length === 0) return false;
  382. const calcResult = this.calculate(phasePay, details);
  383. const updateData = calcResult.filter(x => { return x.calcUpdate; }).map(x => {
  384. return { id: x.id, tp: x.tp, start_tp: x.start_tp, range_tp: x.range_tp, end_tp: x.end_tp };
  385. });
  386. if (updateData.length === 0) return false;
  387. if (transaction) {
  388. await transaction.updateRows(this.tableName, updateData);
  389. } else {
  390. await this.defaultUpdateRows(updateData);
  391. }
  392. return true;
  393. }
  394. _getDefaultData(data, phasePay, parent) {
  395. data.uuid = this.uuid.v4();
  396. data.tid = phasePay.tid;
  397. data.phase_id = phasePay.id;
  398. data.create_user_id = this.ctx.session.sessionUser.accountId;
  399. data.update_user_id = this.ctx.session.sessionUser.accountId;
  400. data.audit_times = phasePay.audit_times;
  401. data.audit_sort = phasePay.audit_max_sort;
  402. data.master_id = this.getMasterKey(phasePay);
  403. if (parent) {
  404. data.is_minus = parent.is_minus;
  405. }
  406. }
  407. async addChild(phasePay, select, count = 1) {
  408. if (select.payType === payType.bqsf || select.payType === payType.bqyf) throw '不可新增子项';
  409. if (select.tree_level >= 2) throw '不可新增子项';
  410. const masterId = this.getMasterKey(phasePay);
  411. const children = await this.getChildrenByParentId(masterId, select[this.setting.kid]);
  412. const maxId = await this._getMaxLid(masterId);
  413. const insertData = [];
  414. for (let i = 1; i <= count ; i++) {
  415. const data = {
  416. tree_id: maxId + i, tree_pid: select.tree_id, tree_order: children.length + 1 + i,
  417. tree_level: select.tree_level + 1, tree_is_leaf: 1
  418. };
  419. data.tree_full_path = select.tree_full_path + '-' + data.tree_id;
  420. this._getDefaultData(data, phasePay, select);
  421. insertData.push(data);
  422. }
  423. const conn = await this.db.beginTransaction();
  424. try {
  425. const result = await conn.insert(this.tableName, insertData);
  426. if (children.length === 0) {
  427. await conn.update(this.tableName, { id: select.id, is_leaf: false });
  428. }
  429. await conn.commit();
  430. } catch(err) {
  431. conn.rollback();
  432. throw err;
  433. }
  434. this._cacheMaxLid(masterId, maxId + 1);
  435. // 查询应返回的结果
  436. const resultData = {};
  437. resultData.create = await this.getNextsData(masterId, select.tree_id, children.length);
  438. if (children.length === 0) resultData.update = await this.getDataByKid(masterId, select.tree_id);
  439. return resultData;
  440. }
  441. async addNext(phasePay, select, count = 1) {
  442. const masterId = this.getMasterKey(phasePay);
  443. this.transaction = await this.db.beginTransaction();
  444. try {
  445. if (select) await this._updateChildrenOrder(masterId, select[this.setting.pid], select[this.setting.order] + 1, count);
  446. const newDatas = [];
  447. const maxId = await this._getMaxLid(masterId);
  448. for (let i = 1; i < count + 1; i++) {
  449. const newData = {};
  450. newData[this.setting.kid] = maxId + i;
  451. newData[this.setting.pid] = select ? select[this.setting.pid] : this.rootId;
  452. newData[this.setting.level] = select ? select[this.setting.level] : 1;
  453. newData[this.setting.order] = select ? select[this.setting.order] + i : i;
  454. newData[this.setting.fullPath] = newData[this.setting.level] > 1
  455. ? select[this.setting.fullPath].replace('-' + select[this.setting.kid], '-' + newData[this.setting.kid])
  456. : newData[this.setting.kid] + '';
  457. newData[this.setting.isLeaf] = 1;
  458. this._getDefaultData(newData, phasePay);
  459. newDatas.push(newData);
  460. }
  461. const insertResult = await this.transaction.insert(this.tableName, newDatas);
  462. this._cacheMaxLid(masterId, maxId + count);
  463. if (insertResult.affectedRows !== count) throw '新增节点数据错误';
  464. await this.transaction.commit();
  465. this.transaction = null;
  466. } catch (err) {
  467. await this.transaction.rollback();
  468. this.transaction = null;
  469. throw err;
  470. }
  471. if (select) {
  472. const createData = await this.getChildBetween(masterId, select[this.setting.pid], select[this.setting.order], select[this.setting.order] + count + 1);
  473. const updateData = await this.getNextsData(masterId, select[this.setting.pid], select[this.setting.order] + count);
  474. return {create: createData, update: updateData};
  475. } else {
  476. const createData = await this.getChildBetween(masterId, -1, 0, count + 1);
  477. return {create: createData};
  478. }
  479. }
  480. async addDetailNode(phasePay, targetId, count = 1) {
  481. if (!phasePay) return null;
  482. const select = targetId ? await this.getDataByKid(this.getMasterKey(phasePay), targetId) : null;
  483. if (targetId && !select) throw '新增节点数据错误';
  484. if (select[this.setting.level] === 1) {
  485. return await this.addChild(phasePay, select, count);
  486. } else {
  487. return await this.addNext(phasePay, select, count);
  488. }
  489. }
  490. async upMoveDetailNode(phasePay, targetId, count = 1) {
  491. const masterId = this.getMasterKey(phasePay);
  492. return await this.upMoveNode(masterId, targetId, count);
  493. }
  494. async downMoveDetailNode(phasePay, targetId, count = 1) {
  495. const masterId = this.getMasterKey(phasePay);
  496. return await this.downMoveNode(masterId, targetId, count);
  497. }
  498. async deleteDetailNode(phasePay, targetId, count = 1) {
  499. const masterId = this.getMasterKey(phasePay);
  500. return await this.delete(masterId, targetId, count);
  501. }
  502. _filterValidField(id, data) {
  503. const ud = { id };
  504. for (const prop in data) {
  505. if (validField.indexOf(prop) >= 0) {
  506. ud[prop] = data[prop];
  507. }
  508. }
  509. return ud;
  510. }
  511. checkCalc(data) {
  512. const datas = data instanceof Array ? data : [data];
  513. for (const d of datas) {
  514. for (const prop in d) {
  515. if (calcField.indexOf(prop) > 0) return true;
  516. }
  517. }
  518. return false;
  519. }
  520. async updateDetail(phasePay, data) {
  521. const masterId = this.getMasterKey(phasePay);
  522. if (Array.isArray(data)) {
  523. const orgData = await this.getAllDataByCondition({ where: { id: data.map(d => { return d.id; }) } });
  524. const updateDatas = [];
  525. for (const d of data) {
  526. const node = orgData.find(x => { return x.id === d.id; });
  527. if (!node || masterId !== node[this.setting.mid]) throw '提交数据错误';
  528. updateDatas.push(this._filterValidField(node.id, d));
  529. }
  530. if (updateDatas.length > 0) await this.db.updateRows(this.tableName, updateDatas);
  531. } else {
  532. const node = await this.getDataById(data.id);
  533. if (!node || masterId !== node[this.setting.mid]) throw '提交数据错误';
  534. const updateData = this._filterValidField(node.id, data);
  535. await this.db.update(this.tableName, updateData);
  536. }
  537. }
  538. }
  539. module.exports = PhasePayDetail;