ledger.test.js 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125
  1. /**
  2. * 标段--台账 模型 单元测试
  3. *
  4. * @author Mai
  5. * @date 2017/2/1
  6. * @version
  7. */
  8. 'use strict';
  9. const excel = require('js-xlsx');
  10. const _ = require('lodash');
  11. const mockData = {};
  12. /*const testNodeData = [
  13. { ledger_id: 1, ledger_pid: -1, order: 1, level: 1, full_path: '1', code: '1', is_leaf: false },
  14. { ledger_id: 2, ledger_pid: 1, order: 1, level: 2, full_path: '1.2', code: '1-1', is_leaf: false },
  15. { ledger_id: 6, ledger_pid: 2, order: 1, level: 3, full_path: '1.2.6', code: '1-1-1', is_leaf: false },
  16. { ledger_id: 7, ledger_pid: 6, order: 1, level: 4, full_path: '1.2.6.7', code: '202-1', is_leaf: false },
  17. { ledger_id: 10, ledger_pid: 7, order: 2, level: 5, full_path: '1.2.6.7.10', code: '202-1-a', is_leaf: true },
  18. { ledger_id: 9, ledger_pid: 7, order: 1, level: 5, full_path: '1.2.6.7.9', code: '202-1-b', is_leaf: true },
  19. { ledger_id: 8, ledger_pid: 6, order: 2, level: 4, full_path: '1.2.6.8', code: '202-2', is_leaf: false },
  20. { ledger_id: 11, ledger_pid: 8, order: 1, level: 5, full_path: '1.2.6.8.11', code: '202-2-c', is_leaf: true },
  21. { ledger_id: 12, ledger_pid: 8, order: 2, level: 5, full_path: '1.2.6.8.12', code: '202-2-e', is_leaf: true },
  22. { ledger_id: 13, ledger_pid: 2, order: 2, level: 3, full_path: '1.2.13', code: '1-1-2', is_leaf: true },
  23. { ledger_id: 14, ledger_pid: 2, order: 3, level: 3, full_path: '1.2.14', code: '1-1-3', is_leaf: true },
  24. { ledger_id: 3, ledger_pid: 1, order: 2, level: 2, full_path: '1.3', code: '1-2', is_leaf: false },
  25. { ledger_id: 15, ledger_pid: 3, order: 1, level: 3, full_path: '1.3.15', code: '1-2-1', is_leaf: true },
  26. { ledger_id: 4, ledger_pid: 1, order: 3, level: 2, full_path: '1.4', code: '1-3', is_leaf: false },
  27. { ledger_id: 16, ledger_pid: 4, order: 1, level: 3, full_path: '1.4.16', code: '1-3-1', is_leaf: true },
  28. { ledger_id: 5, ledger_pid: 1, order: 4, level: 2, full_path: '1.5', code: '1-4', is_leaf: true },
  29. ];*/
  30. const testNodeData = [
  31. { id: 1, pid: -1, order: 1, level: 1, full_path: '1', code: '1', is_leaf: false },
  32. { id: 2, pid: 1, order: 1, level: 2, full_path: '1.2', code: '1-1', is_leaf: false },
  33. { id: 6, pid: 2, order: 1, level: 3, full_path: '1.2.6', code: '1-1-1', is_leaf: false },
  34. { id: 7, pid: 6, order: 1, level: 4, full_path: '1.2.6.7', code: '202-1', is_leaf: false },
  35. { id: 10, pid: 7, order: 2, level: 5, full_path: '1.2.6.7.10', code: '202-1-a', is_leaf: true },
  36. { id: 9, pid: 7, order: 1, level: 5, full_path: '1.2.6.7.9', code: '202-1-b', is_leaf: true },
  37. { id: 8, pid: 6, order: 2, level: 4, full_path: '1.2.6.8', code: '202-2', is_leaf: false },
  38. { id: 11, pid: 8, order: 1, level: 5, full_path: '1.2.6.8.11', code: '202-2-c', is_leaf: true },
  39. { id: 12, pid: 8, order: 2, level: 5, full_path: '1.2.6.8.12', code: '202-2-e', is_leaf: true },
  40. { id: 13, pid: 2, order: 2, level: 3, full_path: '1.2.13', code: '1-1-2', is_leaf: true },
  41. { id: 14, pid: 2, order: 3, level: 3, full_path: '1.2.14', code: '1-1-3', is_leaf: true },
  42. { id: 3, pid: 1, order: 2, level: 2, full_path: '1.3', code: '1-2', is_leaf: false },
  43. { id: 15, pid: 3, order: 1, level: 3, full_path: '1.3.15', code: '1-2-1', is_leaf: true },
  44. { id: 4, pid: 1, order: 3, level: 2, full_path: '1.4', code: '1-3', is_leaf: false },
  45. { id: 16, pid: 4, order: 1, level: 3, full_path: '1.4.16', code: '1-3-1', is_leaf: true },
  46. { id: 5, pid: 1, order: 4, level: 2, full_path: '1.5', code: '1-4', is_leaf: true },
  47. ];
  48. const { app, assert } = require('egg-mock/bootstrap');
  49. const findById = function(nodes, Id) {
  50. const filters = nodes.filter(function(x) {
  51. return x.ledger_id === Id;
  52. });
  53. return filters.length > 0 ? filters[0] : undefined;
  54. };
  55. describe('test/app/service/ledger.test.js', () => {
  56. // 准备测试数据
  57. // 准备测试数据,新增测试标段
  58. before(function* () {
  59. const ctx = app.mockContext(mockData);
  60. // 模拟登录session
  61. const postData = {
  62. account: '734406061@qq.com',
  63. project: 'T201711273363',
  64. project_password: 'mai654321',
  65. };
  66. ctx.session = {};
  67. const loginResult = yield ctx.service.projectAccount.accountLogin(postData, 2);
  68. assert(loginResult);
  69. mockData.session = ctx.session;
  70. // 模拟打开标段
  71. mockData.tender = {};
  72. const addData = {
  73. name: 'test_ledger',
  74. category: null,
  75. };
  76. const tenderData = yield ctx.service.tender.getDataByCondition({
  77. user_id: ctx.session.sessionUser.accountId,
  78. name: addData.name,
  79. });
  80. if (tenderData) {
  81. mockData.tender.data = tenderData;
  82. } else {
  83. const addResult = yield ctx.service.tender.add(addData);
  84. assert(addResult);
  85. mockData.tender.data = yield ctx.service.tender.getDataByCondition({
  86. user_id: ctx.session.sessionUser.accountId,
  87. name: addData.name,
  88. });
  89. }
  90. mockData.tender.id = mockData.tender.data.id;
  91. mockData.tender.info = yield ctx.service.tenderInfo.getTenderInfo(mockData.tender.id);
  92. ctx.tender = mockData.tender;
  93. // 清理旧测试数据
  94. let result = yield ctx.service.ledger.db.delete(ctx.service.ledger.tableName, { tender_id: ctx.tender.id });
  95. const posResult = yield ctx.service.pos.db.delete(ctx.service.ledger.tableName, { tender_id: ctx.tender.id });
  96. assert(result.affectedRows >= 0 && posResult.affectedRows >= 0);
  97. // 初始化测试基础数据
  98. for (const data of testNodeData) {
  99. data.tender_id = ctx.tender.id;
  100. }
  101. result = yield ctx.service.ledger.add(testNodeData, ctx.tender.id);
  102. assert(result);
  103. ctx.service.ledger.cache.set('tender_node_maxId:' + ctx.tender.id, 16, 'EX', ctx.app.config.cacheTime);
  104. });
  105. // 统一校验
  106. afterEach(function* () {
  107. const ctx = app.mockContext(mockData);
  108. const nodes = yield ctx.service.ledger.getData(ctx.tender.id);
  109. const paths = _.uniqBy(nodes, 'full_path');
  110. assert(nodes.length === paths.length);
  111. });
  112. /* 期望运行结果:
  113. 1
  114. ├── 1-1
  115. │ ├── 1-1-1
  116. │ │ ├── 202-1
  117. │ │ │ ├── 202-1-a
  118. │ │ │ └── 202-1-b
  119. │ │ └── 202-2
  120. │ │ ├── 202-2-c
  121. │ │ └── 202-1-3
  122. │ ├── 1-1-2
  123. │ └── 1-1-3
  124. ├── 1-2
  125. │ └── 1-2-1
  126. ├── 1-3
  127. │ └── 1-3-1
  128. └── 1-4
  129. */
  130. // 测试R类方法
  131. it('test getData', function* () {
  132. const ctx = app.mockContext(mockData);
  133. // 查询前4层节点
  134. const result1 = yield ctx.service.ledger.getData(ctx.tender.id);
  135. assert(result1.length === 12);
  136. // 查询前3层节点
  137. const result2 = yield ctx.service.ledger.getData(ctx.tender.id, 3);
  138. assert(result2.length === 10);
  139. });
  140. it('test getDataByNodeId', function* () {
  141. const ctx = app.mockContext(mockData);
  142. // 查询节点202-1
  143. const node = yield ctx.service.ledger.getDataByNodeId(ctx.tender.id, 7);
  144. assert(node);
  145. assert(node.code === '202-1');
  146. assert(node.full_path === '1.2.6.7');
  147. });
  148. it('test getDataByNodeIds', function* () {
  149. const ctx = app.mockContext(mockData);
  150. // 查询节点202-1-a与201-1-b
  151. const result = yield ctx.service.ledger.getDataByNodeIds(ctx.tender.id, [10, 9]);
  152. assert(result.length === 2);
  153. let node = findById(result, 10);
  154. assert(node.code === '202-1-a');
  155. node = findById(result, 9);
  156. assert(node.full_path === '1.2.6.7.9');
  157. });
  158. it('test getDataByIds', function* () {
  159. const ctx = app.mockContext(mockData);
  160. // 查询节点202-1
  161. const node = yield ctx.service.ledger.getDataByNodeId(ctx.tender.id, 7);
  162. const result = yield ctx.service.ledger.getDataByIds([node.id]);
  163. assert(result.length === 1);
  164. assert(node.code === result[0].code);
  165. assert(node.full_path === result[0].full_path);
  166. });
  167. it('test getLastChildData', function* () {
  168. const ctx = app.mockContext(mockData);
  169. // 查询节点202-1最后一个子节点
  170. const result = yield ctx.service.ledger.getLastChildData(ctx.tender.id, 7);
  171. assert(result.ledger_id === 10);
  172. assert(result.full_path === '1.2.6.7.10');
  173. });
  174. it('test getDataByParentAndOrder', function* () {
  175. const ctx = app.mockContext(mockData);
  176. // 查询节点202-1 第1子节点
  177. const result1 = yield ctx.service.ledger.getDataByParentAndOrder(ctx.tender.id, 8, 1);
  178. assert(result1.ledger_id === 11);
  179. assert(result1.full_path === '1.2.6.8.11');
  180. // 查询节点1-1 第2/3子节点
  181. const result2 = yield ctx.service.ledger.getDataByParentAndOrder(ctx.tender.id, 2, [2, 3]);
  182. assert(result2.length === 2);
  183. let node = findById(result2, 13);
  184. assert(node);
  185. assert(node.code === '1-1-2');
  186. node = findById(result2, 14);
  187. assert(node);
  188. assert(node.code === '1-1-3');
  189. });
  190. it('test getChildrenByParentId', function* () {
  191. const ctx = app.mockContext(mockData);
  192. // 查询节点202-1最后一个子节点
  193. const result = yield ctx.service.ledger.getChildrenByParentId(ctx.tender.id, 8);
  194. assert(result.length === 2);
  195. let node = findById(result, 11);
  196. assert(node);
  197. assert(node.code === '202-2-c');
  198. node = findById(result, 12);
  199. assert(node);
  200. assert(node.full_path === '1.2.6.8.12');
  201. });
  202. it('test getNextsData', function* () {
  203. const ctx = app.mockContext(mockData);
  204. // 查询节点1-1-1的全部子节点
  205. const result = yield ctx.service.ledger.getNextsData(ctx.tender.id, 2, 1);
  206. assert(result.length === 2);
  207. let node = findById(result, 13);
  208. assert(node);
  209. assert(node.code === '1-1-2');
  210. node = findById(result, 14);
  211. assert(node);
  212. assert(node.code === '1-1-3');
  213. });
  214. it('test getDataByFullPath', function* () {
  215. const ctx = app.mockContext(mockData);
  216. // 查询节点202-2及其子节点
  217. const result = yield ctx.service.ledger.getDataByFullPath(ctx.tender.id, '1.2.6.8%');
  218. assert(result.length === 3);
  219. let node = findById(result, 8);
  220. assert(node);
  221. assert(node.code === '202-2');
  222. node = findById(result, 11);
  223. assert(node);
  224. assert(node.code === '202-2-c');
  225. node = findById(result, 12);
  226. assert(node);
  227. assert(node.full_path === '1.2.6.8.12');
  228. // 查询1-1-1的子孙节点
  229. const result1 = yield ctx.service.ledger.getDataByFullPath(ctx.tender.id, '1.2.6.%');
  230. assert(result1.length === 6);
  231. });
  232. it('test getFullLevelDataByFullPath', function* () {
  233. const ctx = app.mockContext(mockData);
  234. // 查询202-2-c及其全部父节点
  235. const result1 = yield ctx.service.ledger.getFullLevelDataByFullPath(ctx.tender.id, '1.2.6.8.11');
  236. assert(result1.length === 5);
  237. const result2 = yield ctx.service.ledger.getFullLevelDataByFullPath(ctx.tender.id, ['1.2.6.8.11', '1.2.6.7.9']);
  238. assert(result2.length === 7);
  239. });
  240. // 测试CUD类方法
  241. // 基本树结构操作
  242. it('test addNode', function* () {
  243. const ctx = app.mockContext(mockData);
  244. // 选中1-1-1,插入节点
  245. const resultData = yield ctx.service.ledger.addNode(ctx.tender.id, 6);
  246. assert(resultData.create.length === 1);
  247. assert(resultData.update.length === 2);
  248. assert(resultData.create[0].is_leaf === 1);
  249. assert(resultData.create[0].ledger_id === 17);
  250. });
  251. /* 期望运行结果:
  252. 1
  253. ├── 1-1
  254. │ ├── 1-1-1
  255. │ │ ├── 202-1
  256. │ │ │ ├── 202-1-a
  257. │ │ │ └── 202-1-b
  258. │ │ └── 202-2
  259. │ │ ├── 202-2-c
  260. │ │ └── 202-1-3
  261. │ ├── new
  262. │ ├── 1-1-2
  263. │ └── 1-1-3
  264. ├── 1-2
  265. │ └── 1-2-1
  266. ├── 1-3
  267. │ └── 1-3-1
  268. └── 1-4
  269. */
  270. it('test deleteNode', function* () {
  271. const ctx = app.mockContext(mockData);
  272. // 选中202-1,删除节点
  273. const resultData = yield ctx.service.ledger.deleteNode(ctx.tender.id, 7);
  274. assert(resultData.delete.length === 3);
  275. assert(resultData.update.length === 1);
  276. });
  277. /* 期望运行结果:
  278. 1
  279. ├── 1-1
  280. │ ├── 1-1-1
  281. │ │ └── 202-2
  282. │ │ ├── 202-2-c
  283. │ │ └── 202-2-e
  284. │ ├── new
  285. │ ├── 1-1-2
  286. │ └── 1-1-3
  287. ├── 1-2
  288. │ └── 1-2-1
  289. ├── 1-3
  290. │ └── 1-3-1
  291. └── 1-4
  292. */
  293. it('test upMoveNode', function* () {
  294. const ctx = app.mockContext(mockData);
  295. // 选中202-2-e上移
  296. const resultData = yield ctx.service.ledger.upMoveNode(ctx.tender.id, 12);
  297. resultData.update.sort(function(x, y) {
  298. return x.order - y.order;
  299. });
  300. assert(resultData.update.length === 2);
  301. assert(resultData.update[0].code === '202-2-e');
  302. });
  303. /* 期望运行结果:
  304. 1
  305. ├── 1-1
  306. │ ├── 1-1-1
  307. │ │ └── 202-2
  308. │ │ ├── 202-2-c
  309. │ │ └── 202-2-e
  310. │ ├── new
  311. │ ├── 1-1-2
  312. │ └── 1-1-3
  313. ├── 1-2
  314. │ └── 1-2-1
  315. ├── 1-3
  316. │ └── 1-3-1
  317. └── 1-4
  318. */
  319. it('test downMoveNode', function* () {
  320. const ctx = app.mockContext(mockData);
  321. // 选中202-2-e下移
  322. const resultData = yield ctx.service.ledger.downMoveNode(ctx.tender.id, 12);
  323. resultData.update.sort(function(x, y) {
  324. return x.order - y.order;
  325. });
  326. assert(resultData.update.length === 2);
  327. assert(resultData.update[0].code === '202-2-c');
  328. });
  329. /* 期望运行结果:
  330. 1
  331. ├── 1-1
  332. │ ├── 1-1-1
  333. │ │ └── 202-2
  334. │ │ ├── 202-2-c
  335. │ │ └── 202-2-e
  336. │ ├── new
  337. │ ├── 1-1-2
  338. │ └── 1-1-3
  339. ├── 1-2
  340. │ └── 1-2-1
  341. ├── 1-3
  342. │ └── 1-3-1
  343. └── 1-4
  344. */
  345. it('test upLevelNode', function* () {
  346. const ctx = app.mockContext(mockData);
  347. // 选中 1-1-2 升级
  348. const resultData = yield ctx.service.ledger.upLevelNode(ctx.tender.id, 13);
  349. assert(resultData);
  350. assert(resultData.update.length === 6);
  351. let node = findById(resultData.update, 13);
  352. assert(node.full_path === '1.13');
  353. assert(node.ledger_pid === 1);
  354. assert(!node.is_leaf);
  355. node = findById(resultData.update, 14);
  356. assert(node.ledger_pid === 13);
  357. assert(node.full_path === '1.13.14');
  358. node = findById(resultData.update, 3);
  359. assert(node.order === 3);
  360. node = findById(resultData.update, 4);
  361. assert(node.order === 4);
  362. node = findById(resultData.update, 5);
  363. assert(node.order === 5);
  364. });
  365. /* 期望运行结果:
  366. 1
  367. ├── 1-1
  368. │ ├── 1-1-1
  369. │ │ └── 202-2
  370. │ │ ├── 202-2-c
  371. │ │ └── 202-2-e
  372. │ └── new
  373. ├── 1-1-2
  374. │ └── 1-1-3
  375. ├── 1-2
  376. │ └── 1-2-1
  377. ├── 1-3
  378. │ └── 1-3-1
  379. └── 1-4
  380. */
  381. it('test downLevelNode', function* () {
  382. const ctx = app.mockContext(mockData);
  383. // 选中1-3 降级
  384. const resultData = yield ctx.service.ledger.downLevelNode(ctx.tender.id, 4);
  385. // 1-2/1-3/1-3-1/1-4修改
  386. assert(resultData.update.length === 4);
  387. let node = findById(resultData.update, 4);
  388. assert(node.full_path === '1.3.4');
  389. assert(node.ledger_pid === 3);
  390. assert(node.level === 3);
  391. assert(node.order === 2);
  392. node = findById(resultData.update, 16);
  393. assert(node.level === 4);
  394. assert(node.full_path === '1.3.4.16');
  395. node = findById(resultData.update, 5);
  396. assert(node.order === 4);
  397. });
  398. /* 期望运行结果:
  399. 1
  400. ├── 1-1
  401. │ ├── 1-1-1
  402. │ │ └── 202-2
  403. │ │ ├── 202-2-c
  404. │ │ └── 202-2-e
  405. │ └── new
  406. ├── 1-1-2
  407. │ └── 1-1-3
  408. ├── 1-2
  409. │ ├── 1-2-1
  410. │ └── 1-3
  411. │ └── 1-3-1
  412. └── 1-4
  413. */
  414. // 复制整块
  415. it('test pasteBlock', function* () {
  416. const ctx = app.mockContext(mockData);
  417. // 选中1-2-1, 粘贴1-1-1和new
  418. const node = yield ctx.service.ledger.getDataByNodeId(ctx.tender.id, 15);
  419. const resultData = yield ctx.service.ledger.pasteBlock(ctx.tender.id, 15, [6, 17]);
  420. const create = _.sortBy(resultData.ledger.create, ['level', 'order']);
  421. assert(create.length === 5);
  422. const node1 = _.find(create, {code: '1-1-1'});
  423. assert(node1.order === 2);
  424. assert(node1.level === 3);
  425. assert(node1.full_path === node.full_path.replace('-' + node.ledger_id, '-' + node1.ledger_id));
  426. const node2 = _.find(create, function (c) {
  427. return c.ledger_pid === node.ledger_pid && c.ledger_id !== node1.ledger_id;
  428. });
  429. assert(node2.order === 3);
  430. assert(node2.level === 3);
  431. assert(node2.full_path === node.full_path.replace('-' + node.ledger_id, '-' + node2.ledger_id));
  432. assert(resultData.ledger.update.length === 1);
  433. assert(resultData.ledger.update[0].order === 4);
  434. assert(resultData.pos.length === 0);
  435. });
  436. /* 期望运行结果:
  437. 1
  438. ├── 1-1
  439. │ ├── 1-1-1
  440. │ │ └── 202-2
  441. │ │ ├── 202-2-c
  442. │ │ └── 202-2-e
  443. │ └── new
  444. ├── 1-1-2
  445. │ └── 1-1-3
  446. ├── 1-2
  447. │ ├── 1-2-1
  448. │ ├── 1-1-1
  449. │ │ └── 202-2
  450. │ │ ├── 202-2-c
  451. │ │ └── 202-2-e
  452. │ ├── new
  453. │ └── 1-3
  454. │ └── 1-3-1
  455. └── 1-4
  456. */
  457. // 增量计算
  458. it('test updateCalc - update 1', function* () {
  459. const ctx = app.mockContext(mockData);
  460. // 计算需使用清单精度、小数位数
  461. ctx.tender = {id: ctx.tender.id};
  462. ctx.tender.data = yield ctx.service.tender.getTender(ctx.tender.id);
  463. ctx.tender.info = yield ctx.service.tenderInfo.getTenderInfo(ctx.tender.id);
  464. // 修改202-2-e(1-1-1下)(id=12)的quantity为2.00000001, unit_price位3.0000005
  465. const qty = 2.00000001, fQty = ctx.helper.round(qty, ctx.tender.info.precision.other.value);
  466. const up = 3.0000005, fUp = ctx.helper.round(up, ctx.tender.info.decimal.up);
  467. const tp = 6.00000103, fTp = ctx.helper.mul(fQty, fUp);
  468. const node1 = yield ctx.service.ledger.getDataByNodeId(ctx.tender.id, 12);
  469. assert(node1);
  470. const resultData = yield ctx.service.ledger.updateCalc(ctx.tender.id, {
  471. id: node1.id,
  472. tender_id: node1.tender_id,
  473. ledger_id: node1.ledger_id,
  474. sgfh_qty: qty,
  475. unit_price: up
  476. });
  477. assert(resultData.update.length === 1);
  478. let node = findById(resultData.update, 12);
  479. assert(node.sgfh_qty === fQty);
  480. assert(node.quantity === fQty);
  481. assert(node.unit_price === fUp);
  482. assert(node.sgfh_tp === fTp);
  483. assert(node.total_price == fTp);
  484. });
  485. /* 期望运行结果:
  486. 1
  487. ├── 1-1
  488. │ ├── 1-1-1
  489. │ │ └── 202-2
  490. │ │ ├── 202-2-c
  491. │ │ └── 202-2-e 2 3 6
  492. │ └── 1-1-4
  493. ├── 1-1-2
  494. │ └── 1-1-3
  495. ├── 1-2
  496. │ ├── 1-2-1
  497. │ ├── 1-2-2
  498. │ │ └── 202-2
  499. │ │ ├── 202-2-c
  500. │ │ └── 202-2-e
  501. │ ├── 1-2-3
  502. │ └── 1-3
  503. │ └── 1-3-1
  504. └── 1-4
  505. */
  506. it('test updateCalc - update N', function* () {
  507. const ctx = app.mockContext(mockData);
  508. // 计算需使用清单精度、小数位数
  509. ctx.tender = {id: ctx.tender.id};
  510. ctx.tender.data = yield ctx.service.tender.getTender(ctx.tender.id);
  511. ctx.tender.info = yield ctx.service.tenderInfo.getTenderInfo(ctx.tender.id);
  512. // 修改202-2-c(1-1-1下)(id=11)的quantity为4.00000025, unit_price为6.0000083
  513. // 202-2-c(1-2-2下)(id=20)的quantity为2.0000001, unit_price为5.000065
  514. // 202-2-e(1-2-2下)(id=21)的quantity为8.0000579, unit_price为4.0000086
  515. const qty = [4.00000025, 2.0000001, 8.0000579];
  516. const up = [6.0000083, 5.000065, 4.0000086];
  517. const tp = [24.0000347, 10.0001305, 32.0003004];
  518. // 实际结果
  519. const fQty = [], fUp = [], fTp = [];
  520. for (const q of qty) {
  521. fQty.push(ctx.helper.round(q, ctx.tender.info.precision.other.value));
  522. }
  523. for (const p of up) {
  524. fUp.push(ctx.helper.round(p, ctx.tender.info.decimal.up));
  525. }
  526. for (const i in qty) {
  527. fTp.push(ctx.helper.mul(fQty[i], fUp[i]));
  528. }
  529. const node1 = yield ctx.service.ledger.getDataByNodeId(ctx.tender.id, 11);
  530. assert(node1);
  531. const node2 = yield ctx.service.ledger.getDataByNodeId(ctx.tender.id, 20);
  532. assert(node2);
  533. const node3 = yield ctx.service.ledger.getDataByNodeId(ctx.tender.id, 21);
  534. assert(node3);
  535. const resultData = yield ctx.service.ledger.updateCalc(ctx.tender.id, [{
  536. id: node1.id,
  537. tender_id: node1.tender_id,
  538. ledger_id: node1.ledger_id,
  539. sgfh_qty: qty[0],
  540. unit_price: up[0]
  541. }, {
  542. id: node2.id,
  543. tender_id: node2.tender_id,
  544. ledger_id: node2.ledger_id,
  545. sjcl_qty: qty[1],
  546. unit_price: up[1]
  547. }, {
  548. id: node3.id,
  549. tender_id: node3.tender_id,
  550. ledger_id: node3.ledger_id,
  551. qtcl_qty: qty[2],
  552. unit_price: up[2]
  553. }]);
  554. assert(resultData.update.length === 3);
  555. let node = findById(resultData.update, 11);
  556. assert(node.sgfh_qty === fQty[0]);
  557. assert(node.quantity === fQty[0]);
  558. assert(node.unit_price === fUp[0]);
  559. assert(node.sgfh_tp === fTp[0]);
  560. assert(node.total_price === fTp[0]);
  561. node = findById(resultData.update, 20);
  562. assert(node.sjcl_qty === fQty[1]);
  563. assert(node.quantity === fQty[1]);
  564. assert(node.unit_price === fUp[1]);
  565. assert(node.sjcl_tp === fTp[1]);
  566. assert(node.total_price === fTp[1]);
  567. node = findById(resultData.update, 21);
  568. assert(node.qtcl_qty === fQty[2]);
  569. assert(node.quantity === fQty[2]);
  570. assert(node.unit_price === fUp[2]);
  571. assert(node.qtcl_tp === fTp[2]);
  572. assert(node.total_price === fTp[2]);
  573. });
  574. /* 期望运行结果:
  575. 1
  576. ├── 1-1
  577. │ ├── 1-1-1
  578. │ │ └── 202-2
  579. │ │ ├── 202-2-c 4 6 24
  580. │ │ └── 202-2-e 2 3 6
  581. │ └── 1-1-4
  582. ├── 1-1-2
  583. │ └── 1-1-3
  584. ├── 1-2
  585. │ ├── 1-2-1
  586. │ ├── 1-2-2
  587. │ │ └── 202-2
  588. │ │ ├── 202-2-c 2 5 10
  589. │ │ └── 202-2-e 8 4 32
  590. │ ├── 1-2-3
  591. │ └── 1-3
  592. │ └── 1-3-1
  593. └── 1-4
  594. */
  595. // 复制整块+实时计算
  596. it('test pasteBlock - with Increment Calculate', function* () {
  597. const ctx = app.mockContext(mockData);
  598. // 选中1-1-4, 粘贴202-2(1-1-1下)
  599. const resultData = yield ctx.service.ledger.pasteBlock(ctx.tender.id, 17, [8]);
  600. assert(resultData.ledger.create.length === 3);
  601. assert(resultData.ledger.update.length === 0);
  602. });
  603. /* 期望运行结果:
  604. 1
  605. ├── 1-1
  606. │ ├── 1-1-1
  607. │ │ └── 202-2
  608. │ │ ├── 202-2-c 4 6 24
  609. │ │ └── 202-2-e 2 3 6
  610. │ ├── 1-1-4
  611. │ └── 202-2
  612. │ ├── 202-2-c 4 6 24
  613. │ └── 202-2-e 2 3 6
  614. ├── 1-1-2
  615. │ └── 1-1-3
  616. ├── 1-2
  617. │ ├── 1-2-1
  618. │ ├── 1-2-2
  619. │ │ └── 202-2
  620. │ │ ├── 202-2-c 2 5 10
  621. │ │ └── 202-2-e 8 4 32
  622. │ ├── 1-2-3
  623. │ └── 1-3
  624. │ └── 1-3-1
  625. └── 1-4
  626. */
  627. // 树结构基本操作+实时计算
  628. it('test downLevel - with Increment Calculate', function* () {
  629. const ctx = app.mockContext(mockData);
  630. // 选中202-2(1-1-4后兄弟节点) 降级
  631. const resultData = yield ctx.service.ledger.downLevelNode(ctx.tender.id, 23);
  632. assert(resultData.update.length === 4);
  633. });
  634. /* 期望运行结果:
  635. 1
  636. ├── 1-1
  637. │ ├── 1-1-1
  638. │ │ └── 202-2
  639. │ │ ├── 202-2-c 4 6 24
  640. │ │ └── 202-2-e 2 3 6
  641. │ └── 1-1-4
  642. │ └── 202-2
  643. │ ├── 202-2-c 4 6 24
  644. │ └── 202-2-e 2 3 6
  645. ├── 1-1-2
  646. │ └── 1-1-3
  647. ├── 1-2
  648. │ ├── 1-2-1
  649. │ ├── 1-2-2
  650. │ │ └── 202-2
  651. │ │ ├── 202-2-c 2 5 10
  652. │ │ └── 202-2-e 8 4 32
  653. │ ├── 1-2-3
  654. │ └── 1-3
  655. │ └── 1-3-1
  656. └── 1-4
  657. */
  658. it('test upLevel - with Increment Calculate', function* () {
  659. const ctx = app.mockContext(mockData);
  660. yield ctx.service.ledger.pasteBlock(ctx.tender.id, 23, [23]);
  661. /* 期望运行结果:
  662. 1
  663. ├── 1-1
  664. │ ├── 1-1-1
  665. │ │ └── 202-2
  666. │ │ ├── 202-2-c 4 6 24
  667. │ │ └── 202-2-e 2 3 6
  668. │ └── 1-1-4
  669. │ ├── 202-2
  670. │ │ ├── 202-2-c 4 6 24
  671. │ │ └── 202-2-e 2 3 6
  672. │ └── 202-2
  673. │ ├── 202-2-c 4 6 24
  674. │ └── 202-2-e 2 3 6
  675. ├── 1-1-2
  676. │ └── 1-1-3
  677. ├── 1-2
  678. │ ├── 1-2-1
  679. │ ├── 1-2-2
  680. │ │ └── 202-2
  681. │ │ ├── 202-2-c 2 5 10
  682. │ │ └── 202-2-e 8 4 32
  683. │ ├── 1-2-3
  684. │ └── 1-3
  685. │ └── 1-3-1
  686. └── 1-4
  687. */
  688. // 选中202-2-c(1-1-4下)(id=23)升级
  689. const resultData = yield ctx.service.ledger.upLevelNode(ctx.tender.id, 23);
  690. assert(resultData.update.length === 7);
  691. });
  692. /* 期望运行结果:
  693. 1
  694. ├── 1-1
  695. │ ├── 1-1-1
  696. │ │ └── 202-2
  697. │ │ ├── 202-2-c 4 6 24
  698. │ │ └── 202-2-e 2 3 6
  699. │ ├── 1-1-4
  700. │ └── 202-2
  701. │ ├── 202-2-c 4 6 24
  702. │ ├── 202-2-e 2 3 6
  703. │ └── 202-2
  704. │ ├── 202-2-c 4 6 24
  705. │ └── 202-2-e 2 3 6
  706. ├── 1-1-2
  707. │ └── 1-1-3
  708. ├── 1-2
  709. │ ├── 1-2-1
  710. │ ├── 1-2-2
  711. │ │ └── 202-2
  712. │ │ ├── 202-2-c 2 5 10
  713. │ │ └── 202-2-e 8 4 32
  714. │ ├── 1-2-3
  715. │ └── 1-3
  716. │ └── 1-3-1
  717. └── 1-4
  718. */
  719. it('test deleteNode - with Increment Calculate', function* () {
  720. const ctx = app.mockContext(mockData);
  721. // 选中202-2-c(1-2-2下)(id=20),删除节点
  722. const node = yield ctx.service.ledger.getDataByCondition({
  723. tender_id: ctx.tender.id,
  724. code: '202-2-c',
  725. level: 5,
  726. });
  727. const resultData = yield ctx.service.ledger.deleteNode(ctx.tender.id, node.ledger_id);
  728. assert(resultData.delete.length === 1);
  729. assert(resultData.update.length === 1);
  730. });
  731. /* 期望运行结果:
  732. 1
  733. ├── 1-1
  734. │ ├── 1-1-1
  735. │ │ └── 202-2
  736. │ │ ├── 202-2-c 4 6 24
  737. │ │ └── 202-2-e 2 3 6
  738. │ ├── 1-1-4
  739. │ └── 202-2
  740. │ ├── 202-2-c 4 6 24
  741. │ ├── 202-2-e 2 3 6
  742. │ └── 202-2
  743. │ ├── 202-2-c 4 6 24
  744. │ └── 202-2-e 2 3 6
  745. ├── 1-1-2
  746. │ └── 1-1-3
  747. ├── 1-2
  748. │ ├── 1-2-1
  749. │ ├── 1-2-2
  750. │ │ └── 202-2
  751. │ │ └── 202-2-e 8 4 32
  752. │ ├── 1-2-3
  753. │ └── 1-3
  754. │ └── 1-3-1
  755. └── 1-4
  756. */
  757. // 从标准库添加数据
  758. // 检查添加,直接添加为选中节点子节点
  759. it('test addStdNode', function* () {
  760. const ctx = app.mockContext(mockData);
  761. // 选中1-1-4
  762. const selectData = yield ctx.service.ledger.getDataByCondition({ tender_id: ctx.tender.id, code: '1-1-4' });
  763. assert(selectData);
  764. // 从标准库中添加1-1-5
  765. const condition1 = { list_id: 1, code: '1-1-5' };
  766. const libData1 = yield ctx.service.stdChapter.getDataByCondition(condition1);
  767. assert(libData1);
  768. const stdData1 = yield ctx.service.stdChapter.getDataByDataId(1, libData1.chapter_id);
  769. assert(stdData1);
  770. assert(stdData1.id === libData1.id);
  771. const result1 = yield ctx.service.ledger.addStdNode(ctx.tender.id, selectData.ledger_id, stdData1);
  772. assert(result1);
  773. assert(result1.create.length === 1);
  774. assert(result1.update.length === 1);
  775. // 从标准库中添加101-1
  776. });
  777. /* 期望运行结果:
  778. 1
  779. ├── 1-1
  780. │ ├── 1-1-1
  781. │ │ └── 202-2
  782. │ │ ├── 202-2-c 4 6 24
  783. │ │ └── 202-2-e 2 3 6
  784. │ ├── 1-1-4
  785. │ ├── 1-1-5
  786. │ └── 202-2
  787. │ ├── 202-2-c 4 6 24
  788. │ ├── 202-2-e 2 3 6
  789. │ └── 202-2
  790. │ ├── 202-2-c 4 6 24
  791. │ └── 202-2-e 2 3 6
  792. ├── 1-1-2
  793. │ └── 1-1-3
  794. ├── 1-2
  795. │ ├── 1-2-1
  796. │ ├── 1-2-2
  797. │ │ └── 202-2
  798. │ │ └── 202-2-e 8 4 32
  799. │ ├── 1-2-3
  800. │ └── 1-3
  801. │ └── 1-3-1
  802. └── 1-4
  803. */
  804. it('test addStdNodeWithParent', function* () {
  805. const ctx = app.mockContext(mockData);
  806. // 从标准库添加1-4-2-1
  807. const condition1 = { list_id: 1, code: '1-4-2-1'};
  808. const libData1 = yield ctx.service.stdChapter.getDataByCondition(condition1);
  809. assert(libData1);
  810. const stdData1 = yield ctx.service.stdChapter.getDataByDataId(1, libData1.chapter_id);
  811. assert(stdData1);
  812. assert(stdData1.id === libData1.id);
  813. const result1 = yield ctx.service.ledger.addStdNodeWithParent(ctx.tender.id, stdData1, ctx.service.stdChapter);
  814. assert(result1);
  815. assert(result1.create.length === 4);
  816. assert(!result1.update || result1.update.length === 0);
  817. assert(!result1.expand || result1.expand.length === 0);
  818. // 从标准库添加1-4-2-1-2
  819. const condition2 = { list_id: 1, code: '1-4-2-1-2'};
  820. const libData2 = yield ctx.service.stdChapter.getDataByCondition(condition2);
  821. assert(libData2);
  822. const stdData2 = yield ctx.service.stdChapter.getDataByDataId(1, libData2.chapter_id);
  823. assert(stdData2);
  824. assert(stdData2.id === libData2.id);
  825. const result2 = yield ctx.service.ledger.addStdNodeWithParent(ctx.tender.id, stdData2, ctx.service.stdChapter);
  826. assert(result2);
  827. assert(result2.create.length === 1);
  828. assert(result2.update.length === 1);
  829. assert(result2.update[0].code === '1-4-2-1');
  830. assert(!result2.update[0].is_leaf);
  831. // 从标准库添加1-4-2-1-1
  832. const condition3 = { list_id: 1, code: '1-4-2-1-1'};
  833. const libData3 = yield ctx.service.stdChapter.getDataByCondition(condition3);
  834. assert(libData3);
  835. const stdData3 = yield ctx.service.stdChapter.getDataByDataId(1, libData3.chapter_id);
  836. assert(stdData3);
  837. assert(stdData3.id === libData3.id);
  838. const result3 = yield ctx.service.ledger.addStdNodeWithParent(ctx.tender.id, stdData3, ctx.service.stdChapter);
  839. assert(result3);
  840. assert(result3.create.length === 1);
  841. assert(result3.create[0].order === 1);
  842. assert(result3.update.length === 1);
  843. assert(result3.update[0].code === '1-4-2-1-2');
  844. assert(result3.update[0].order === 2);
  845. });
  846. /* 期望运行结果:
  847. 1
  848. ├── 1-1
  849. │ ├── 1-1-1
  850. │ │ └── 202-2
  851. │ │ ├── 202-2-c 4.00000025 6.0000083 24.0000347
  852. │ │ └── 202-2-e 2.00000001 3.0000005 6.00000103
  853. │ ├── 1-1-4
  854. │ ├── 1-1-5
  855. │ └── 202-2
  856. │ ├── 202-2-c 4.00000025 6.0000083 24.0000347
  857. │ ├── 202-2-e 2.00000001 3.0000005 6.00000103
  858. │ └── 202-2
  859. │ ├── 202-2-c 4.00000025 6.0000083 24.0000347
  860. │ └── 202-2-e 2.00000001 3.0000005 6.00000103
  861. ├── 1-1-2
  862. │ └── 1-1-3
  863. ├── 1-2
  864. │ ├── 1-2-1
  865. │ ├── 1-2-2
  866. │ │ └── 202-2
  867. │ │ └── 202-2-e 8.0000579 4.0000086 32.0003004
  868. │ ├── 1-2-3
  869. │ └── 1-3
  870. │ └── 1-3-1
  871. └── 1-4
  872. └── 1-4-2
  873. └── 1-4-2-1
  874. ├── 1-4-2-1-1
  875. └── 1-4-2-1-2
  876. */
  877. // 批量插入
  878. it('test batchInsertChild', function* () {
  879. const ctx = app.mockContext(mockData);
  880. const batchData = [
  881. {
  882. b_code: 401-1, name: 'A1', unit: 'B1', price: 2,
  883. pos: [{name: 'X1', quantity: 1}, {name: 'X2', quantity: 2}],
  884. },
  885. {
  886. b_code: 402-1, name: 'A2', unit: 'B2', price: 3,
  887. pos: [{name: 'X1', quantity: 3}, {name: 'X2', quantity: 4}],
  888. },
  889. ];
  890. // 选中1-1-3(id=14)
  891. const result = yield ctx.service.ledger.batchInsertChild(ctx.tender.id, 14, batchData);
  892. assert(result.ledger.create.length === 2);
  893. let node = _.find(result.ledger.create, {name: 'A1'});
  894. assert(node.quantity === 3);
  895. assert(node.total_price === 6);
  896. node = _.find(result.ledger.create, {name: 'A2'});
  897. assert(node.quantity === 7);
  898. assert(node.total_price === 21);
  899. assert(result.pos.length === 4);
  900. });
  901. /* 期望运行结果:
  902. 1
  903. ├── 1-1
  904. │ ├── 1-1-1
  905. │ │ └── 202-2
  906. │ │ ├── 202-2-c 4.00000025 6.0000083 24.0000347
  907. │ │ └── 202-2-e 2.00000001 3.0000005 6.00000103
  908. │ ├── 1-1-4
  909. │ ├── 1-1-5
  910. │ └── 202-2
  911. │ ├── 202-2-c 4.00000025 6.0000083 24.0000347
  912. │ ├── 202-2-e 2.00000001 3.0000005 6.00000103
  913. │ └── 202-2
  914. │ ├── 202-2-c 4.00000025 6.0000083 24.0000347
  915. │ └── 202-2-e 2.00000001 3.0000005 6.00000103
  916. ├── 1-1-2
  917. │ └── 1-1-3
  918. │ ├── 401-1 2 3 6
  919. │ │ ├── (pos)X1 1
  920. │ │ └── (pos)X1 2
  921. │ └── 402-1 3 7 21
  922. │ ├── (pos)X1 3
  923. │ └── (pos)X2 4
  924. ├── 1-2
  925. │ ├── 1-2-1
  926. │ ├── 1-2-2
  927. │ │ └── 202-2
  928. │ │ └── 202-2-e 8.0000579 4.0000086 32.0003004
  929. │ ├── 1-2-3
  930. │ └── 1-3
  931. │ └── 1-3-1
  932. └── 1-4
  933. └── 1-4-2
  934. └── 1-4-2-1
  935. ├── 1-4-2-1-1
  936. └── 1-4-2-1-2
  937. */
  938. // 批量插入
  939. it('test batchInsertNext', function* () {
  940. const ctx = app.mockContext(mockData);
  941. const batchData = [
  942. {
  943. b_code: 403-1, name: 'A3', unit: 'B1', price: 2,
  944. pos: [{name: 'Y1', quantity: 5}, {name: 'Y2', quantity: 6}],
  945. },
  946. {
  947. b_code: 404-1, name: 'A4', unit: 'B2', price: 3,
  948. pos: [{name: 'Y1', quantity: 7}, {name: 'Y2', quantity: 8}],
  949. },
  950. ];
  951. // 选中1-1-3(id=14)
  952. const result = yield ctx.service.ledger.batchInsertNext(ctx.tender.id, 14, batchData);
  953. assert(result.ledger.create.length === 2);
  954. let node = _.find(result.ledger.create, {name: 'A3'});
  955. assert(node.quantity === 11);
  956. assert(node.total_price === 22);
  957. node = _.find(result.ledger.create, {name: 'A4'});
  958. assert(node.quantity === 15);
  959. assert(node.total_price === 45);
  960. assert(result.pos.length === 4);
  961. });
  962. /* 期望运行结果:
  963. 1
  964. ├── 1-1
  965. │ ├── 1-1-1
  966. │ │ └── 202-2
  967. │ │ ├── 202-2-c 4.00000025 6.0000083 24.0000347
  968. │ │ └── 202-2-e 2.00000001 3.0000005 6.00000103
  969. │ ├── 1-1-4
  970. │ ├── 1-1-5
  971. │ └── 202-2
  972. │ ├── 202-2-c 4.00000025 6.0000083 24.0000347
  973. │ ├── 202-2-e 2.00000001 3.0000005 6.00000103
  974. │ └── 202-2
  975. │ ├── 202-2-c 4.00000025 6.0000083 24.0000347
  976. │ └── 202-2-e 2.00000001 3.0000005 6.00000103
  977. ├── 1-1-2
  978. │ ├── 1-1-3
  979. │ │ ├── 401-1 2 3 6
  980. │ │ │ ├── (pos)X1 1
  981. │ │ │ └── (pos)X1 2
  982. │ │ └── 402-1 3 7 21
  983. │ │ ├── (pos)X1 3
  984. │ │ └── (pos)X2 4
  985. │ ├── 403-1 2 11 22
  986. │ │ ├── (pos)Y1 5
  987. │ │ └── (pos)Y2 6
  988. │ └── 404-1 3 15 45
  989. │ ├── (pos)Y1 7
  990. │ └── (pos)Y2 8
  991. ├── 1-2
  992. │ ├── 1-2-1
  993. │ ├── 1-2-2
  994. │ │ └── 202-2
  995. │ │ └── 202-2-e 8.0000579 4.0000086 32.0003004
  996. │ ├── 1-2-3
  997. │ └── 1-3
  998. │ └── 1-3-1
  999. └── 1-4
  1000. └── 1-4-2
  1001. └── 1-4-2-1
  1002. ├── 1-4-2-1-1
  1003. └── 1-4-2-1-2
  1004. */
  1005. // 测试统计类方法
  1006. it('test addUpChildren', function* () {
  1007. const ctx = app.mockContext(mockData);
  1008. // 统计202-2(id=23)前两个子节点的金额
  1009. const result1 = yield ctx.service.ledger.addUpChildren(ctx.tender.id, 23, 2, '<=');
  1010. assert(result1 && result1 === 30);
  1011. // 数据库不再存储父项金额,以下两个查询不能获得实际金额
  1012. // 统计202-2(id=23)后两个子节点的金额
  1013. //const result2 = yield ctx.service.ledger.addUpChildren(ctx.tender.id, 23, 2, '>=');
  1014. //assert(result2 && result2.toFixed(8) == 36.00003676);
  1015. // 统计202-2(id=23)全部子节点的金额
  1016. //const result3 = yield ctx.service.ledger.addUpChildren(ctx.tender.id, 23, 0, '>');
  1017. //assert(result3 && result3.toFixed(8) == 60.00007146);
  1018. });
  1019. // 测试导入excel 在\lib\analysis_excel.test.js中进行单元测试
  1020. // 小数位数策略示例:
  1021. /* 先加总再保留3位小数:
  1022. 1 35.585
  1023. ├── 1-1 35.585
  1024. │ ├── 1-1-1 35.585
  1025. │ │ └── 202-2 35.585
  1026. │ │ ├── 202-2-c 4.25 6.83 29.028(29.0275)
  1027. │ │ └── 202-2-e 2.15 3.05 6.558(6.5575)
  1028. │ └── 1-1-3
  1029. ├── 1-1-2
  1030. │ └── 1-1-3
  1031. ├── 1-2
  1032. │ ├── 1-2-1
  1033. │ ├── 1-2-2
  1034. │ │ └── 202-2
  1035. │ │ ├── 202-2-c
  1036. │ │ └── 202-2-e
  1037. │ ├── 1-2-3
  1038. │ └── 1-3
  1039. │ └── 1-3-1
  1040. └── 1-4
  1041. */
  1042. /* 先保留3位小数再加总:
  1043. 1 35.586
  1044. ├── 1-1 35.586
  1045. │ ├── 1-1-1 35.586
  1046. │ │ └── 202-2 35.586
  1047. │ │ ├── 202-2-c 4.25 6.83 29.028(29.0275)
  1048. │ │ └── 202-2-e 2.15 3.05 6.558(6.5575)
  1049. │ └── 1-1-3
  1050. ├── 1-1-2
  1051. │ └── 1-1-3
  1052. ├── 1-2
  1053. │ ├── 1-2-1
  1054. │ ├── 1-2-2
  1055. │ │ └── 202-2
  1056. │ │ ├── 202-2-c
  1057. │ │ └── 202-2-e
  1058. │ ├── 1-2-3
  1059. │ └── 1-3
  1060. │ └── 1-3-1
  1061. └── 1-4
  1062. */
  1063. });