@tasenor/common-node 1.9.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/.eslintrc.js +4 -0
  2. package/LICENSE +21 -0
  3. package/dist/tasenor-common-node/src/cli.d.ts +81 -0
  4. package/dist/tasenor-common-node/src/cli.js +242 -0
  5. package/dist/tasenor-common-node/src/cli.js.map +1 -0
  6. package/dist/tasenor-common-node/src/commands/account.d.ts +12 -0
  7. package/dist/tasenor-common-node/src/commands/account.js +58 -0
  8. package/dist/tasenor-common-node/src/commands/account.js.map +1 -0
  9. package/dist/tasenor-common-node/src/commands/balance.d.ts +11 -0
  10. package/dist/tasenor-common-node/src/commands/balance.js +117 -0
  11. package/dist/tasenor-common-node/src/commands/balance.js.map +1 -0
  12. package/dist/tasenor-common-node/src/commands/db.d.ts +14 -0
  13. package/dist/tasenor-common-node/src/commands/db.js +69 -0
  14. package/dist/tasenor-common-node/src/commands/db.js.map +1 -0
  15. package/dist/tasenor-common-node/src/commands/entry.d.ts +13 -0
  16. package/dist/tasenor-common-node/src/commands/entry.js +106 -0
  17. package/dist/tasenor-common-node/src/commands/entry.js.map +1 -0
  18. package/dist/tasenor-common-node/src/commands/import.d.ts +17 -0
  19. package/dist/tasenor-common-node/src/commands/import.js +140 -0
  20. package/dist/tasenor-common-node/src/commands/import.js.map +1 -0
  21. package/dist/tasenor-common-node/src/commands/importer.d.ts +13 -0
  22. package/dist/tasenor-common-node/src/commands/importer.js +71 -0
  23. package/dist/tasenor-common-node/src/commands/importer.js.map +1 -0
  24. package/dist/tasenor-common-node/src/commands/index.d.ts +191 -0
  25. package/dist/tasenor-common-node/src/commands/index.js +482 -0
  26. package/dist/tasenor-common-node/src/commands/index.js.map +1 -0
  27. package/dist/tasenor-common-node/src/commands/period.d.ts +12 -0
  28. package/dist/tasenor-common-node/src/commands/period.js +48 -0
  29. package/dist/tasenor-common-node/src/commands/period.js.map +1 -0
  30. package/dist/tasenor-common-node/src/commands/plugin.d.ts +15 -0
  31. package/dist/tasenor-common-node/src/commands/plugin.js +78 -0
  32. package/dist/tasenor-common-node/src/commands/plugin.js.map +1 -0
  33. package/dist/tasenor-common-node/src/commands/report.d.ts +11 -0
  34. package/dist/tasenor-common-node/src/commands/report.js +96 -0
  35. package/dist/tasenor-common-node/src/commands/report.js.map +1 -0
  36. package/dist/tasenor-common-node/src/commands/settings.d.ts +10 -0
  37. package/dist/tasenor-common-node/src/commands/settings.js +64 -0
  38. package/dist/tasenor-common-node/src/commands/settings.js.map +1 -0
  39. package/dist/tasenor-common-node/src/commands/stock.d.ts +8 -0
  40. package/dist/tasenor-common-node/src/commands/stock.js +73 -0
  41. package/dist/tasenor-common-node/src/commands/stock.js.map +1 -0
  42. package/dist/tasenor-common-node/src/commands/tag.d.ts +13 -0
  43. package/dist/tasenor-common-node/src/commands/tag.js +89 -0
  44. package/dist/tasenor-common-node/src/commands/tag.js.map +1 -0
  45. package/dist/tasenor-common-node/src/commands/tx.d.ts +12 -0
  46. package/dist/tasenor-common-node/src/commands/tx.js +81 -0
  47. package/dist/tasenor-common-node/src/commands/tx.js.map +1 -0
  48. package/dist/tasenor-common-node/src/commands/user.d.ts +12 -0
  49. package/dist/tasenor-common-node/src/commands/user.js +52 -0
  50. package/dist/tasenor-common-node/src/commands/user.js.map +1 -0
  51. package/dist/tasenor-common-node/src/database/BookkeeperImporter.d.ts +77 -0
  52. package/dist/tasenor-common-node/src/database/BookkeeperImporter.js +343 -0
  53. package/dist/tasenor-common-node/src/database/BookkeeperImporter.js.map +1 -0
  54. package/dist/tasenor-common-node/src/database/DB.d.ts +51 -0
  55. package/dist/tasenor-common-node/src/database/DB.js +354 -0
  56. package/dist/tasenor-common-node/src/database/DB.js.map +1 -0
  57. package/dist/tasenor-common-node/src/database/index.d.ts +7 -0
  58. package/dist/tasenor-common-node/src/database/index.js +8 -0
  59. package/dist/tasenor-common-node/src/database/index.js.map +1 -0
  60. package/dist/tasenor-common-node/src/doccer.d.ts +29 -0
  61. package/dist/tasenor-common-node/src/doccer.js +30 -0
  62. package/dist/tasenor-common-node/src/doccer.js.map +1 -0
  63. package/dist/tasenor-common-node/src/error.d.ts +30 -0
  64. package/dist/tasenor-common-node/src/error.js +35 -0
  65. package/dist/tasenor-common-node/src/error.js.map +1 -0
  66. package/dist/tasenor-common-node/src/export/Exporter.d.ts +69 -0
  67. package/dist/tasenor-common-node/src/export/Exporter.js +123 -0
  68. package/dist/tasenor-common-node/src/export/Exporter.js.map +1 -0
  69. package/dist/tasenor-common-node/src/export/TasenorExporter.d.ts +55 -0
  70. package/dist/tasenor-common-node/src/export/TasenorExporter.js +135 -0
  71. package/dist/tasenor-common-node/src/export/TasenorExporter.js.map +1 -0
  72. package/dist/tasenor-common-node/src/export/TilitinExporter.d.ts +71 -0
  73. package/dist/tasenor-common-node/src/export/TilitinExporter.js +290 -0
  74. package/dist/tasenor-common-node/src/export/TilitinExporter.js.map +1 -0
  75. package/dist/tasenor-common-node/src/export/index.d.ts +8 -0
  76. package/dist/tasenor-common-node/src/export/index.js +9 -0
  77. package/dist/tasenor-common-node/src/export/index.js.map +1 -0
  78. package/dist/tasenor-common-node/src/import/TextFileProcessHandler.d.ts +104 -0
  79. package/dist/tasenor-common-node/src/import/TextFileProcessHandler.js +354 -0
  80. package/dist/tasenor-common-node/src/import/TextFileProcessHandler.js.map +1 -0
  81. package/dist/tasenor-common-node/src/import/TransactionImportConnector.d.ts +38 -0
  82. package/dist/tasenor-common-node/src/import/TransactionImportConnector.js +27 -0
  83. package/dist/tasenor-common-node/src/import/TransactionImportConnector.js.map +1 -0
  84. package/dist/tasenor-common-node/src/import/TransactionImportHandler.d.ts +173 -0
  85. package/dist/tasenor-common-node/src/import/TransactionImportHandler.js +733 -0
  86. package/dist/tasenor-common-node/src/import/TransactionImportHandler.js.map +1 -0
  87. package/dist/tasenor-common-node/src/import/TransactionRules.d.ts +238 -0
  88. package/dist/tasenor-common-node/src/import/TransactionRules.js +522 -0
  89. package/dist/tasenor-common-node/src/import/TransactionRules.js.map +1 -0
  90. package/dist/tasenor-common-node/src/import/TransactionUI.d.ts +181 -0
  91. package/dist/tasenor-common-node/src/import/TransactionUI.js +482 -0
  92. package/dist/tasenor-common-node/src/import/TransactionUI.js.map +1 -0
  93. package/dist/tasenor-common-node/src/import/TransferAnalyzer.d.ts +324 -0
  94. package/dist/tasenor-common-node/src/import/TransferAnalyzer.js +1379 -0
  95. package/dist/tasenor-common-node/src/import/TransferAnalyzer.js.map +1 -0
  96. package/dist/tasenor-common-node/src/import/index.d.ts +11 -0
  97. package/dist/tasenor-common-node/src/import/index.js +12 -0
  98. package/dist/tasenor-common-node/src/import/index.js.map +1 -0
  99. package/dist/tasenor-common-node/src/index.d.ts +12 -0
  100. package/dist/tasenor-common-node/src/index.js +13 -0
  101. package/dist/tasenor-common-node/src/index.js.map +1 -0
  102. package/dist/tasenor-common-node/src/net/crypto.d.ts +33 -0
  103. package/dist/tasenor-common-node/src/net/crypto.js +63 -0
  104. package/dist/tasenor-common-node/src/net/crypto.js.map +1 -0
  105. package/dist/tasenor-common-node/src/net/git.d.ts +49 -0
  106. package/dist/tasenor-common-node/src/net/git.js +137 -0
  107. package/dist/tasenor-common-node/src/net/git.js.map +1 -0
  108. package/dist/tasenor-common-node/src/net/index.d.ts +10 -0
  109. package/dist/tasenor-common-node/src/net/index.js +11 -0
  110. package/dist/tasenor-common-node/src/net/index.js.map +1 -0
  111. package/dist/tasenor-common-node/src/net/middleware.d.ts +61 -0
  112. package/dist/tasenor-common-node/src/net/middleware.js +220 -0
  113. package/dist/tasenor-common-node/src/net/middleware.js.map +1 -0
  114. package/dist/tasenor-common-node/src/net/tokens.d.ts +50 -0
  115. package/dist/tasenor-common-node/src/net/tokens.js +141 -0
  116. package/dist/tasenor-common-node/src/net/tokens.js.map +1 -0
  117. package/dist/tasenor-common-node/src/net/vault.d.ts +67 -0
  118. package/dist/tasenor-common-node/src/net/vault.js +145 -0
  119. package/dist/tasenor-common-node/src/net/vault.js.map +1 -0
  120. package/dist/tasenor-common-node/src/plugins/BackendPlugin.d.ts +91 -0
  121. package/dist/tasenor-common-node/src/plugins/BackendPlugin.js +165 -0
  122. package/dist/tasenor-common-node/src/plugins/BackendPlugin.js.map +1 -0
  123. package/dist/tasenor-common-node/src/plugins/DataPlugin.d.ts +13 -0
  124. package/dist/tasenor-common-node/src/plugins/DataPlugin.js +26 -0
  125. package/dist/tasenor-common-node/src/plugins/DataPlugin.js.map +1 -0
  126. package/dist/tasenor-common-node/src/plugins/ImportPlugin.d.ts +188 -0
  127. package/dist/tasenor-common-node/src/plugins/ImportPlugin.js +204 -0
  128. package/dist/tasenor-common-node/src/plugins/ImportPlugin.js.map +1 -0
  129. package/dist/tasenor-common-node/src/plugins/ReportPlugin.d.ts +132 -0
  130. package/dist/tasenor-common-node/src/plugins/ReportPlugin.js +393 -0
  131. package/dist/tasenor-common-node/src/plugins/ReportPlugin.js.map +1 -0
  132. package/dist/tasenor-common-node/src/plugins/SchemePlugin.d.ts +34 -0
  133. package/dist/tasenor-common-node/src/plugins/SchemePlugin.js +47 -0
  134. package/dist/tasenor-common-node/src/plugins/SchemePlugin.js.map +1 -0
  135. package/dist/tasenor-common-node/src/plugins/ServicePlugin.d.ts +80 -0
  136. package/dist/tasenor-common-node/src/plugins/ServicePlugin.js +168 -0
  137. package/dist/tasenor-common-node/src/plugins/ServicePlugin.js.map +1 -0
  138. package/dist/tasenor-common-node/src/plugins/ToolPlugin.d.ts +27 -0
  139. package/dist/tasenor-common-node/src/plugins/ToolPlugin.js +37 -0
  140. package/dist/tasenor-common-node/src/plugins/ToolPlugin.js.map +1 -0
  141. package/dist/tasenor-common-node/src/plugins/index.d.ts +13 -0
  142. package/dist/tasenor-common-node/src/plugins/index.js +14 -0
  143. package/dist/tasenor-common-node/src/plugins/index.js.map +1 -0
  144. package/dist/tasenor-common-node/src/plugins/plugins.d.ts +101 -0
  145. package/dist/tasenor-common-node/src/plugins/plugins.js +292 -0
  146. package/dist/tasenor-common-node/src/plugins/plugins.js.map +1 -0
  147. package/dist/tasenor-common-node/src/process/Process.d.ts +108 -0
  148. package/dist/tasenor-common-node/src/process/Process.js +335 -0
  149. package/dist/tasenor-common-node/src/process/Process.js.map +1 -0
  150. package/dist/tasenor-common-node/src/process/ProcessConnector.d.ts +24 -0
  151. package/dist/tasenor-common-node/src/process/ProcessConnector.js +28 -0
  152. package/dist/tasenor-common-node/src/process/ProcessConnector.js.map +1 -0
  153. package/dist/tasenor-common-node/src/process/ProcessFile.d.ts +69 -0
  154. package/dist/tasenor-common-node/src/process/ProcessFile.js +145 -0
  155. package/dist/tasenor-common-node/src/process/ProcessFile.js.map +1 -0
  156. package/dist/tasenor-common-node/src/process/ProcessHandler.d.ts +60 -0
  157. package/dist/tasenor-common-node/src/process/ProcessHandler.js +73 -0
  158. package/dist/tasenor-common-node/src/process/ProcessHandler.js.map +1 -0
  159. package/dist/tasenor-common-node/src/process/ProcessStep.d.ts +52 -0
  160. package/dist/tasenor-common-node/src/process/ProcessStep.js +78 -0
  161. package/dist/tasenor-common-node/src/process/ProcessStep.js.map +1 -0
  162. package/dist/tasenor-common-node/src/process/ProcessingSystem.d.ts +60 -0
  163. package/dist/tasenor-common-node/src/process/ProcessingSystem.js +182 -0
  164. package/dist/tasenor-common-node/src/process/ProcessingSystem.js.map +1 -0
  165. package/dist/tasenor-common-node/src/process/index.d.ts +11 -0
  166. package/dist/tasenor-common-node/src/process/index.js +12 -0
  167. package/dist/tasenor-common-node/src/process/index.js.map +1 -0
  168. package/dist/tasenor-common-node/src/reports/conversions.d.ts +8 -0
  169. package/dist/tasenor-common-node/src/reports/conversions.js +47 -0
  170. package/dist/tasenor-common-node/src/reports/conversions.js.map +1 -0
  171. package/dist/tasenor-common-node/src/reports/index.d.ts +6 -0
  172. package/dist/tasenor-common-node/src/reports/index.js +7 -0
  173. package/dist/tasenor-common-node/src/reports/index.js.map +1 -0
  174. package/dist/tasenor-common-node/src/server/ISPDemoServer.d.ts +43 -0
  175. package/dist/tasenor-common-node/src/server/ISPDemoServer.js +112 -0
  176. package/dist/tasenor-common-node/src/server/ISPDemoServer.js.map +1 -0
  177. package/dist/tasenor-common-node/src/server/api.d.ts +15 -0
  178. package/dist/tasenor-common-node/src/server/api.js +27 -0
  179. package/dist/tasenor-common-node/src/server/api.js.map +1 -0
  180. package/dist/tasenor-common-node/src/server/index.d.ts +7 -0
  181. package/dist/tasenor-common-node/src/server/index.js +8 -0
  182. package/dist/tasenor-common-node/src/server/index.js.map +1 -0
  183. package/dist/tasenor-common-node/src/server/router.d.ts +5 -0
  184. package/dist/tasenor-common-node/src/server/router.js +37 -0
  185. package/dist/tasenor-common-node/src/server/router.js.map +1 -0
  186. package/dist/tasenor-common-node/src/system.d.ts +27 -0
  187. package/dist/tasenor-common-node/src/system.js +95 -0
  188. package/dist/tasenor-common-node/src/system.js.map +1 -0
  189. package/dist/tasenor-common-node/src/testing/ProcessingSystemMock.d.ts +21 -0
  190. package/dist/tasenor-common-node/src/testing/ProcessingSystemMock.js +33 -0
  191. package/dist/tasenor-common-node/src/testing/ProcessingSystemMock.js.map +1 -0
  192. package/dist/tasenor-common-node/src/testing/UnitTestImportConnector.d.ts +24 -0
  193. package/dist/tasenor-common-node/src/testing/UnitTestImportConnector.js +68 -0
  194. package/dist/tasenor-common-node/src/testing/UnitTestImportConnector.js.map +1 -0
  195. package/dist/tasenor-common-node/src/testing/UnitTester.d.ts +64 -0
  196. package/dist/tasenor-common-node/src/testing/UnitTester.js +199 -0
  197. package/dist/tasenor-common-node/src/testing/UnitTester.js.map +1 -0
  198. package/dist/tasenor-common-node/src/testing/index.d.ts +4 -0
  199. package/dist/tasenor-common-node/src/testing/index.js +5 -0
  200. package/dist/tasenor-common-node/src/testing/index.js.map +1 -0
  201. package/dist/tasenor-common-node/src/testing/test-handlers.d.ts +13 -0
  202. package/dist/tasenor-common-node/src/testing/test-handlers.js +52 -0
  203. package/dist/tasenor-common-node/src/testing/test-handlers.js.map +1 -0
  204. package/dist/tasenor-common-node/tests/TransactionRules.spec.d.ts +1 -0
  205. package/dist/tasenor-common-node/tests/TransactionRules.spec.js +64 -0
  206. package/dist/tasenor-common-node/tests/TransactionRules.spec.js.map +1 -0
  207. package/dist/tasenor-common-node/tests/TransferAnalyzer-account-address.spec.d.ts +1 -0
  208. package/dist/tasenor-common-node/tests/TransferAnalyzer-account-address.spec.js +80 -0
  209. package/dist/tasenor-common-node/tests/TransferAnalyzer-account-address.spec.js.map +1 -0
  210. package/dist/tasenor-common-node/tests/TransferAnalyzer-buying-and-selling.spec.d.ts +1 -0
  211. package/dist/tasenor-common-node/tests/TransferAnalyzer-buying-and-selling.spec.js +342 -0
  212. package/dist/tasenor-common-node/tests/TransferAnalyzer-buying-and-selling.spec.js.map +1 -0
  213. package/dist/tasenor-common-node/tests/TransferAnalyzer-loans.spec.d.ts +1 -0
  214. package/dist/tasenor-common-node/tests/TransferAnalyzer-loans.spec.js +174 -0
  215. package/dist/tasenor-common-node/tests/TransferAnalyzer-loans.spec.js.map +1 -0
  216. package/dist/tasenor-common-node/tests/TransferAnalyzer-multiple-null-amounts.spec.d.ts +1 -0
  217. package/dist/tasenor-common-node/tests/TransferAnalyzer-multiple-null-amounts.spec.js +175 -0
  218. package/dist/tasenor-common-node/tests/TransferAnalyzer-multiple-null-amounts.spec.js.map +1 -0
  219. package/dist/tasenor-common-node/tests/password.spec.d.ts +1 -0
  220. package/dist/tasenor-common-node/tests/password.spec.js +8 -0
  221. package/dist/tasenor-common-node/tests/password.spec.js.map +1 -0
  222. package/dist/tasenor-common-node/tests/tokens.spec.d.ts +1 -0
  223. package/dist/tasenor-common-node/tests/tokens.spec.js +49 -0
  224. package/dist/tasenor-common-node/tests/tokens.spec.js.map +1 -0
  225. package/dist/tasenor-common-node/tests/vault.spec.d.ts +1 -0
  226. package/dist/tasenor-common-node/tests/vault.spec.js +19 -0
  227. package/dist/tasenor-common-node/tests/vault.spec.js.map +1 -0
  228. package/dist/tasenor-common-plugins/src/CoinbaseImport/backend/CoinbaseHandler.d.ts +11 -0
  229. package/dist/tasenor-common-plugins/src/CoinbaseImport/backend/CoinbaseHandler.js +30 -0
  230. package/dist/tasenor-common-plugins/src/CoinbaseImport/backend/CoinbaseHandler.js.map +1 -0
  231. package/dist/tasenor-common-plugins/src/IncomeAndExpenses/backend/index.d.ts +5 -0
  232. package/dist/tasenor-common-plugins/src/IncomeAndExpenses/backend/index.js +350 -0
  233. package/dist/tasenor-common-plugins/src/IncomeAndExpenses/backend/index.js.map +1 -0
  234. package/dist/tasenor-common-plugins/src/KrakenImport/backend/KrakenHandler.d.ts +23 -0
  235. package/dist/tasenor-common-plugins/src/KrakenImport/backend/KrakenHandler.js +83 -0
  236. package/dist/tasenor-common-plugins/src/KrakenImport/backend/KrakenHandler.js.map +1 -0
  237. package/dist/tasenor-common-plugins/src/LynxImport/backend/LynxHandler.d.ts +28 -0
  238. package/dist/tasenor-common-plugins/src/LynxImport/backend/LynxHandler.js +340 -0
  239. package/dist/tasenor-common-plugins/src/LynxImport/backend/LynxHandler.js.map +1 -0
  240. package/dist/tasenor-common-plugins/src/NordeaImport/backend/NordeaHandler.d.ts +11 -0
  241. package/dist/tasenor-common-plugins/src/NordeaImport/backend/NordeaHandler.js +39 -0
  242. package/dist/tasenor-common-plugins/src/NordeaImport/backend/NordeaHandler.js.map +1 -0
  243. package/dist/tasenor-common-plugins/src/NordnetImport/backend/NordnetHandler.d.ts +17 -0
  244. package/dist/tasenor-common-plugins/src/NordnetImport/backend/NordnetHandler.js +66 -0
  245. package/dist/tasenor-common-plugins/src/NordnetImport/backend/NordnetHandler.js.map +1 -0
  246. package/dist/tasenor-common-plugins/src/TITOImport/backend/TITOHandler.d.ts +13 -0
  247. package/dist/tasenor-common-plugins/src/TITOImport/backend/TITOHandler.js +241 -0
  248. package/dist/tasenor-common-plugins/src/TITOImport/backend/TITOHandler.js.map +1 -0
  249. package/jest.config.js +1 -0
  250. package/package.json +62 -0
  251. package/src/cli.ts +267 -0
  252. package/src/commands/account.ts +69 -0
  253. package/src/commands/balance.ts +131 -0
  254. package/src/commands/db.ts +84 -0
  255. package/src/commands/entry.ts +117 -0
  256. package/src/commands/import.ts +160 -0
  257. package/src/commands/importer.ts +84 -0
  258. package/src/commands/index.ts +534 -0
  259. package/src/commands/period.ts +59 -0
  260. package/src/commands/plugin.ts +95 -0
  261. package/src/commands/report.ts +113 -0
  262. package/src/commands/settings.ts +75 -0
  263. package/src/commands/stock.ts +80 -0
  264. package/src/commands/tag.ts +102 -0
  265. package/src/commands/tx.ts +93 -0
  266. package/src/commands/user.ts +65 -0
  267. package/src/database/BookkeeperImporter.ts +358 -0
  268. package/src/database/DB.ts +396 -0
  269. package/src/database/index.ts +7 -0
  270. package/src/doccer.ts +29 -0
  271. package/src/error.ts +32 -0
  272. package/src/export/Exporter.ts +136 -0
  273. package/src/export/TasenorExporter.ts +144 -0
  274. package/src/export/TilitinExporter.ts +302 -0
  275. package/src/export/index.ts +8 -0
  276. package/src/import/TextFileProcessHandler.ts +384 -0
  277. package/src/import/TransactionImportConnector.ts +65 -0
  278. package/src/import/TransactionImportHandler.ts +819 -0
  279. package/src/import/TransactionRules.ts +570 -0
  280. package/src/import/TransactionUI.ts +520 -0
  281. package/src/import/TransferAnalyzer.ts +1450 -0
  282. package/src/import/index.ts +11 -0
  283. package/src/index.ts +12 -0
  284. package/src/net/crypto.ts +69 -0
  285. package/src/net/git.ts +151 -0
  286. package/src/net/index.ts +10 -0
  287. package/src/net/middleware.ts +261 -0
  288. package/src/net/tokens.ts +140 -0
  289. package/src/net/vault.ts +161 -0
  290. package/src/plugins/BackendPlugin.ts +188 -0
  291. package/src/plugins/DataPlugin.ts +29 -0
  292. package/src/plugins/ImportPlugin.ts +211 -0
  293. package/src/plugins/ReportPlugin.ts +443 -0
  294. package/src/plugins/SchemePlugin.ts +56 -0
  295. package/src/plugins/ServicePlugin.ts +188 -0
  296. package/src/plugins/ToolPlugin.ts +44 -0
  297. package/src/plugins/index.ts +13 -0
  298. package/src/plugins/plugins.ts +345 -0
  299. package/src/process/Process.ts +368 -0
  300. package/src/process/ProcessConnector.ts +45 -0
  301. package/src/process/ProcessFile.ts +169 -0
  302. package/src/process/ProcessHandler.ts +94 -0
  303. package/src/process/ProcessStep.ts +100 -0
  304. package/src/process/ProcessingSystem.ts +202 -0
  305. package/src/process/index.ts +11 -0
  306. package/src/reports/conversions.ts +52 -0
  307. package/src/reports/index.ts +6 -0
  308. package/src/server/ISPDemoServer.ts +122 -0
  309. package/src/server/api.ts +37 -0
  310. package/src/server/index.ts +7 -0
  311. package/src/server/router.ts +60 -0
  312. package/src/system.ts +96 -0
  313. package/src/testing/ProcessingSystemMock.ts +45 -0
  314. package/src/testing/UnitTestImportConnector.ts +86 -0
  315. package/src/testing/UnitTester.ts +231 -0
  316. package/src/testing/index.ts +4 -0
  317. package/src/testing/test-handlers.ts +55 -0
  318. package/tests/TransactionRules.spec.ts +73 -0
  319. package/tests/TransferAnalyzer-account-address.spec.ts +87 -0
  320. package/tests/TransferAnalyzer-buying-and-selling.spec.ts +354 -0
  321. package/tests/TransferAnalyzer-loans.spec.ts +197 -0
  322. package/tests/TransferAnalyzer-multiple-null-amounts.spec.ts +181 -0
  323. package/tests/password.spec.ts +8 -0
  324. package/tests/tokens.spec.ts +52 -0
  325. package/tests/vault.spec.ts +20 -0
  326. package/tsconfig.json +13 -0
@@ -0,0 +1,733 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ import { TransactionApplyResults, debug, realNegative, realPositive, NO_SEGMENT, num, Directions, less, mergeTags, log } from '@dataplug/tasenor-common';
3
+ import { TransferAnalyzer } from './TransferAnalyzer';
4
+ import hash from 'object-hash';
5
+ import { TransactionUI } from './TransactionUI';
6
+ import { TransactionRules } from './TransactionRules';
7
+ import { isTransactionImportConnector } from './TransactionImportConnector';
8
+ import { TextFileProcessHandler } from './TextFileProcessHandler';
9
+ import { BadState, InvalidFile, NotImplemented, SystemError } from '../error';
10
+ import clone from 'clone';
11
+ /**
12
+ * Core functionality for all transaction import handlers.
13
+ */
14
+ export class TransactionImportHandler extends TextFileProcessHandler {
15
+ UI;
16
+ rules;
17
+ analyzer;
18
+ constructor(name) {
19
+ super(name);
20
+ this.UI = new TransactionUI(this);
21
+ this.rules = new TransactionRules(this);
22
+ }
23
+ /**
24
+ * By default, we don't support multifile.
25
+ * @param file
26
+ * @returns
27
+ */
28
+ canAppend(file) {
29
+ return false;
30
+ }
31
+ /**
32
+ * Get a single account balance.
33
+ * @param addr
34
+ */
35
+ getBalance(addr) {
36
+ if (!this.analyzer) {
37
+ throw new Error(`Cannot access balance for ${addr} when no analyzer instantiated.`);
38
+ }
39
+ return this.analyzer.getBalance(addr);
40
+ }
41
+ /**
42
+ * Get the translation for the text to the currently configured language.
43
+ * @param text
44
+ * @returns
45
+ */
46
+ async getTranslation(text, language) {
47
+ if (!language) {
48
+ throw new SystemError('Language is compulsory setting for importing, if there are unknowns to ask from UI.');
49
+ }
50
+ return this.system.getTranslation(text, language);
51
+ }
52
+ /**
53
+ * Get the account having matching asset in their code.
54
+ * @param asset
55
+ * @returns
56
+ */
57
+ getAccountCanditates(addr, config) {
58
+ return this.system.connector.getAccountCanditates(addr, config);
59
+ }
60
+ /**
61
+ * Construct grouping for the line data with columns defined using sub class that can generate unique ID per transaction.
62
+ * @param state
63
+ */
64
+ async groupingById(state) {
65
+ state.segments = {};
66
+ for (const fileName of Object.keys(state.files)) {
67
+ // Collect segments from lines.
68
+ for (let n = 0; n < state.files[fileName].lines.length; n++) {
69
+ const line = state.files[fileName].lines[n];
70
+ if (!line.columns || Object.keys(line.columns).length === 0) {
71
+ continue;
72
+ }
73
+ const id = this.segmentId(line);
74
+ if (!id || !state.segments) {
75
+ throw new InvalidFile(`The segment ID for ${JSON.stringify(line)} was not found by ${this.constructor.name}.`);
76
+ }
77
+ if (id === NO_SEGMENT) {
78
+ continue;
79
+ }
80
+ state.segments[id] = state.segments[id] || { id, time: undefined, lines: [] };
81
+ state.segments[id].lines.push({ number: n, file: fileName });
82
+ line.segmentId = id;
83
+ }
84
+ // Calculate time stamps for each segment.
85
+ if (!state.segments) {
86
+ throw new InvalidFile('This cannot happen.');
87
+ }
88
+ Object.values(state.segments).forEach((segment) => {
89
+ const stamps = new Set();
90
+ segment.lines.forEach(segmentLine => {
91
+ const line = state.files[segmentLine.file].lines[segmentLine.number];
92
+ const time = this.time(line);
93
+ if (time) {
94
+ stamps.add(time.getTime());
95
+ }
96
+ });
97
+ if (stamps.size === 0) {
98
+ throw new InvalidFile(`Was not able to find timestamps for lines ${JSON.stringify(segment.lines)}.`);
99
+ }
100
+ if (stamps.size > 1) {
101
+ throw new InvalidFile(`Found more than one (${stamps.size}) canditate for timestamp (${[...stamps]}) from lines ${JSON.stringify(segment.lines)}.`);
102
+ }
103
+ segment.time = new Date([...stamps][0]);
104
+ });
105
+ }
106
+ return state;
107
+ }
108
+ /**
109
+ * Default parser for file data.
110
+ */
111
+ async parse(state, config = {}) {
112
+ switch (this.importOptions.parser) {
113
+ case 'csv':
114
+ if (this.importOptions.csv === undefined) {
115
+ throw new SystemError('No CSV options defined.');
116
+ }
117
+ return this.parseCSV(state, this.importOptions.csv);
118
+ case 'custom':
119
+ if (this.importOptions.custom === undefined) {
120
+ throw new SystemError('No custom options defined.');
121
+ }
122
+ return this.parseCustom(state, this.importOptions.custom);
123
+ default:
124
+ throw new SystemError(`Parser '${this.importOptions.parser}' is not implemented.`);
125
+ }
126
+ }
127
+ /**
128
+ * Default segmentation is parsing CSV and then grouping by segment ID constructed for each line.
129
+ * @param state
130
+ * @param files
131
+ * @returns
132
+ */
133
+ async segmentationCSV(process, state, files) {
134
+ const parsed = await this.parse(state, process.config);
135
+ const newState = await this.groupingById(parsed);
136
+ this.debugSegmentation(newState);
137
+ return newState;
138
+ }
139
+ /**
140
+ * Hook to do some post proccessing for segmentation process. Collects standard fields.
141
+ * @param state
142
+ * @returns
143
+ */
144
+ async segmentationPostProcess(state) {
145
+ const shared = {};
146
+ for (const fileName of Object.keys(state.files)) {
147
+ // Build standard fields.
148
+ const { textField, totalAmountField } = this.importOptions;
149
+ for (let n = 0; n < state.files[fileName].lines.length; n++) {
150
+ const { columns, segmentId } = state.files[fileName].lines[n];
151
+ for (const name of this.importOptions.requiredFields) {
152
+ if (columns[name] === undefined) {
153
+ columns[name] = '';
154
+ }
155
+ }
156
+ for (const name of this.importOptions.numericFields) {
157
+ if (columns[name] !== undefined) {
158
+ // TODO: We need to allow numeric values as well. Might need some syntax fixing here and there.
159
+ columns[name] = (columns[name] === '' ? 0 : num(columns[name]));
160
+ }
161
+ }
162
+ if (this.importOptions.sharedFields) {
163
+ for (const name of this.importOptions.sharedFields) {
164
+ if (columns[name] !== undefined) {
165
+ shared[segmentId] = shared[segmentId] || {};
166
+ if (shared[segmentId][name] === undefined) {
167
+ shared[segmentId][name] = columns[name];
168
+ }
169
+ else {
170
+ throw new Error(`No handling implemented when shared field '${name}' is found from more than one line (${JSON.stringify(shared[segmentId][name])} and ${JSON.stringify(columns[name])}).`);
171
+ }
172
+ }
173
+ }
174
+ }
175
+ if (textField) {
176
+ columns._textField = columns[textField];
177
+ }
178
+ if (totalAmountField) {
179
+ columns._totalAmountField = columns[totalAmountField];
180
+ }
181
+ }
182
+ }
183
+ // Add shared fields.
184
+ for (const fileName of Object.keys(state.files)) {
185
+ for (let n = 0; n < state.files[fileName].lines.length; n++) {
186
+ const { columns, segmentId } = state.files[fileName].lines[n];
187
+ if (shared[segmentId]) {
188
+ Object.assign(columns, shared[segmentId]);
189
+ }
190
+ }
191
+ }
192
+ return state;
193
+ }
194
+ async segmentation(process, state, files) {
195
+ const result = await this.segmentationPostProcess(await this.segmentationCSV(process, state, files));
196
+ return result;
197
+ }
198
+ /**
199
+ * Helper to dump segmentation results.
200
+ */
201
+ debugSegmentation(state) {
202
+ if (state.files) {
203
+ Object.keys(state.files).forEach(fileName => {
204
+ debug('SEGMENTATION', `Segmentation of ${fileName}`);
205
+ debug('SEGMENTATION', state.files[fileName].lines.filter(line => Object.keys(line.columns).length > 0));
206
+ });
207
+ }
208
+ }
209
+ /**
210
+ * Construct a hash for a text line usable as unique segment ID.
211
+ * @param line
212
+ */
213
+ hash(line, columns = undefined) {
214
+ // Trim spaces away before calculating hash.
215
+ if (columns === undefined) {
216
+ columns = Object.keys(line.columns);
217
+ }
218
+ const obj = columns.map(c => [c, line.columns[c]]).filter(entry => entry[1] !== undefined).reduce((prev, cur) => ({ ...prev, [cur[0]]: `${cur[1]}`.trim() }), {});
219
+ return hash.sha1(obj);
220
+ }
221
+ /**
222
+ * Segmentation by ID can use this function to group lines by their ID. By default the hash is used.
223
+ * @param line
224
+ */
225
+ segmentId(line, columns = undefined) {
226
+ if (columns === undefined) {
227
+ columns = Object.keys(line.columns);
228
+ }
229
+ if (line.columns && Object.keys(columns).length) {
230
+ return this.hash(line, columns);
231
+ }
232
+ return NO_SEGMENT;
233
+ }
234
+ /**
235
+ * Find out the timestamp from the line data if any.
236
+ * @param line
237
+ */
238
+ time(line) {
239
+ throw new NotImplemented(`Import class ${this.constructor.name} does not implement time().`);
240
+ }
241
+ /**
242
+ * Default classification constructs lines belonging to each segment and asks subclass to classify them.
243
+ *
244
+ * @param state
245
+ * @param files
246
+ * @returns
247
+ */
248
+ async classification(process, state, files) {
249
+ const newState = {
250
+ stage: 'classified',
251
+ files: state.files,
252
+ segments: state.segments,
253
+ result: {}
254
+ };
255
+ if (state.segments) {
256
+ // Handle segments by date.
257
+ for (const segment of this.sortSegments(state.segments)) {
258
+ const lines = segment.lines.map(fileRef => state.files[fileRef.file].lines[fileRef.number]);
259
+ const result = await this.classifyLines(lines, process.config, state.segments[segment.id]);
260
+ if (newState.result) { // Needed for compiler.
261
+ newState.result[segment.id] = [result];
262
+ }
263
+ }
264
+ }
265
+ this.debugClassification(newState);
266
+ return newState;
267
+ }
268
+ /**
269
+ * Helper to dump classification results.
270
+ */
271
+ debugClassification(state) {
272
+ if (state.result) {
273
+ Object.keys(state.result).forEach(segmentId => {
274
+ if (state.result && state.result[segmentId]) {
275
+ debug('CLASSIFICATION', `Classification of ${segmentId}`);
276
+ debug('CLASSIFICATION', state.result[segmentId]);
277
+ }
278
+ });
279
+ }
280
+ }
281
+ /**
282
+ * By default, use rules to classify.
283
+ * @param lines
284
+ */
285
+ async classifyLines(lines, config, segment) {
286
+ return await this.rules.classifyLines(lines, config, segment);
287
+ }
288
+ /**
289
+ * Collect lines related to the segment.
290
+ * @param state
291
+ * @param segmentId
292
+ */
293
+ getLines(state, segmentId) {
294
+ if (state.segments && state.segments[segmentId]) {
295
+ const segment = state.segments[segmentId];
296
+ const lines = segment.lines.map(line => state.files[line.file].lines[line.number]);
297
+ return lines;
298
+ }
299
+ return null;
300
+ }
301
+ /**
302
+ * Check if all accounts are configured and if not, construct query UI for it.
303
+ * @param state
304
+ * @returns
305
+ */
306
+ async needInputForAnalysis(state, config) {
307
+ if (!state.result || !state.segments) {
308
+ return false;
309
+ }
310
+ const missing = new Set();
311
+ // Use fresh analyzer to avoid messing stock bookkeeping.
312
+ const analyzer = new TransferAnalyzer(this, config, state);
313
+ for (const [segmentId, result] of Object.entries(state.result)) {
314
+ const segment = state.segments[segmentId];
315
+ const items = result;
316
+ // Check if we have accounts.
317
+ for (const transfer of items) {
318
+ for (const acc of await analyzer.collectAccounts(segment, transfer, { findMissing: true })) {
319
+ missing.add(acc);
320
+ }
321
+ }
322
+ // Find out if some of the missing accounts are actual defined as UI query or perhaps already answered.
323
+ for (const address of missing) {
324
+ if (config.answers) {
325
+ const answers = config.answers;
326
+ if ((segmentId in answers) &&
327
+ (`account.${address}` in answers[segmentId]) &&
328
+ (answers[segmentId][`account.${address}`] !== undefined)) {
329
+ missing.delete(address);
330
+ continue;
331
+ }
332
+ }
333
+ const [reason, type, asset] = address.split('.');
334
+ const query = await analyzer.getAccountQuery(reason, type, asset);
335
+ const lines = this.getLines(state, segmentId);
336
+ if (!lines) {
337
+ throw new Error(`Failed to collect lines for segment ${segmentId}.`);
338
+ }
339
+ if (query) {
340
+ const description = await this.UI.describeLines(lines, config.language);
341
+ const question = await this.UI.query(`answer.${segmentId}.account.${address}`, query, [], config.language);
342
+ return new Directions({
343
+ type: 'ui',
344
+ element: {
345
+ type: 'flat',
346
+ elements: [description, question]
347
+ }
348
+ });
349
+ }
350
+ }
351
+ }
352
+ if (!missing.size) {
353
+ return false;
354
+ }
355
+ log(`Need to configure some accounts: ${[...missing].join(', ')}`);
356
+ return this.directionsForMissingAccounts(missing, config);
357
+ }
358
+ /**
359
+ * Study configured accounts and missing accounts and construct appropriate UI query for accounts.
360
+ * @param missing
361
+ * @param config
362
+ * @returns
363
+ */
364
+ async directionsForMissingAccounts(missing, config) {
365
+ // Collect account settings from config.
366
+ const configured = Object.keys(config).filter(key => /^account\.\w+\.\w+\./.test(key));
367
+ // Get reason + type pair grouping and accounts for each group.
368
+ const pairs = {};
369
+ for (const address of configured) {
370
+ const [, reason, type, asset] = address.split('.');
371
+ if (asset !== '*') {
372
+ pairs[`${reason}.${type}`] = pairs[`${reason}.${type}`] || new Set();
373
+ pairs[`${reason}.${type}`].add(`${reason}.${type}.${asset}`);
374
+ }
375
+ }
376
+ for (const address of missing) {
377
+ const [reason, type, asset] = address.split('.');
378
+ pairs[`${reason}.${type}`] = pairs[`${reason}.${type}`] || new Set();
379
+ pairs[`${reason}.${type}`].add(`${reason}.${type}.${asset}`);
380
+ }
381
+ // Check groups and construct query either for single account or grouped accounts.
382
+ const elements = [];
383
+ for (const addresses of Object.values(pairs)) {
384
+ if (addresses.size === 1) {
385
+ if (missing.has([...addresses][0])) {
386
+ elements.push(await this.UI.account(config, [...addresses][0]));
387
+ }
388
+ }
389
+ else {
390
+ let count = 0;
391
+ for (const address of addresses) {
392
+ if (missing.has(address))
393
+ count++;
394
+ }
395
+ if (count) {
396
+ elements.push(await this.UI.accountGroup(config, [...addresses]));
397
+ }
398
+ }
399
+ }
400
+ if (elements.length === 0) {
401
+ return false;
402
+ }
403
+ elements.push(await this.UI.submit('Continue', 1, config.language));
404
+ return new Directions({
405
+ type: 'ui',
406
+ element: {
407
+ type: 'flat',
408
+ elements
409
+ }
410
+ });
411
+ }
412
+ /**
413
+ * Insert custom segments based on answer collection, if necessary.
414
+ */
415
+ async createCustomSegments(state, config) {
416
+ const newState = clone(state);
417
+ if (!newState.result) {
418
+ newState.result = {};
419
+ }
420
+ if (!newState.segments) {
421
+ newState.segments = {};
422
+ }
423
+ if ('answers' in config && '' in config.answers) {
424
+ const answers = config.answers;
425
+ const renamed = await this.getTranslation('note-renamed', config.language);
426
+ const oldName = await this.getTranslation('note-old-name', config.language);
427
+ const newName = await this.getTranslation('note-new-name', config.language);
428
+ if ('' in answers && answers['']) {
429
+ for (const rename of answers['']['asset-renaming'] || []) {
430
+ const transfers = [
431
+ {
432
+ reason: 'trade',
433
+ type: rename.type,
434
+ asset: rename.old,
435
+ data: {
436
+ notes: [renamed, oldName]
437
+ }
438
+ },
439
+ {
440
+ reason: 'trade',
441
+ type: rename.type,
442
+ asset: rename.new,
443
+ data: {
444
+ notes: [renamed, newName]
445
+ }
446
+ }
447
+ ];
448
+ const segment = {
449
+ id: `rename-${rename.type}-${rename.old}-${rename.new}`,
450
+ time: new Date(`${rename.date}T00:00:00.000Z`),
451
+ lines: []
452
+ };
453
+ const td = {
454
+ type: 'transfers',
455
+ transfers
456
+ };
457
+ newState.segments[segment.id] = segment;
458
+ newState.result[segment.id] = [td];
459
+ }
460
+ }
461
+ }
462
+ return newState;
463
+ }
464
+ /**
465
+ * Sort the segments by their date.
466
+ * @param segments
467
+ * @returns
468
+ */
469
+ sortSegments(segments) {
470
+ const time = (entry) => {
471
+ return (typeof entry.time === 'string') ? new Date(entry.time).getTime() : entry.time.getTime();
472
+ };
473
+ return Object.values(segments).sort((a, b) => time(a) - time(b));
474
+ }
475
+ /**
476
+ * Convert transfers to the actual transactions with account numbers.
477
+ * @param state
478
+ * @param files
479
+ */
480
+ async analysis(process, state, files, config) {
481
+ // Insert custom segments to the state.
482
+ state = await this.createCustomSegments(state, config);
483
+ this.analyzer = new TransferAnalyzer(this, config, state);
484
+ if (state.result && state.segments) {
485
+ // Sort segments by timestamp and find the first and the last.
486
+ const segments = this.sortSegments(state.segments);
487
+ let firstTimeStamp;
488
+ if (segments.length) {
489
+ // Look for the first and last valid time stamp.
490
+ const confStartDate = config.firstDate ? new Date(`${config.firstDate}T00:00:00.000Z`) : null;
491
+ for (let i = 0; i < segments.length; i++) {
492
+ const segmentTime = typeof segments[i].time === 'string' ? new Date(segments[i].time) : segments[i].time;
493
+ if (!confStartDate || segmentTime >= confStartDate) {
494
+ firstTimeStamp = segmentTime;
495
+ break;
496
+ }
497
+ }
498
+ if (!firstTimeStamp) {
499
+ throw new Error(`Unable to find any valid time stamps after ${confStartDate}.`);
500
+ }
501
+ await this.analyzer.initialize(firstTimeStamp);
502
+ }
503
+ // Prepare loan account information.
504
+ const debtAccounts = {};
505
+ this.analyzer.getBalances().filter(balance => balance.mayTakeLoan).forEach(balance => {
506
+ debtAccounts[balance.account] = balance;
507
+ });
508
+ // Analyze each segment in chronological order.
509
+ for (const segment of segments) {
510
+ const txDesc = state.result[segment.id];
511
+ if (!txDesc) {
512
+ throw new BadState(`Cannot find results for segment ${segment.id} during analysis (${JSON.stringify(segment)})`);
513
+ }
514
+ for (let i = 0; i < txDesc.length; i++) {
515
+ txDesc[i] = await this.analyze(txDesc[i], segment, config, state, debtAccounts);
516
+ }
517
+ }
518
+ }
519
+ const newState = {
520
+ ...state,
521
+ stage: 'analyzed'
522
+ };
523
+ this.debugAnalysis(newState);
524
+ return newState;
525
+ }
526
+ /**
527
+ * Analyze and construct transaction details from a transaction description.
528
+ * @param txs
529
+ */
530
+ async analyze(txs, segment, config, state, debtAccounts) {
531
+ if (!this.analyzer) {
532
+ throw new SystemError('Calling analyze() without setting up analyzer.');
533
+ }
534
+ let result;
535
+ switch (txs.type) {
536
+ case 'transfers':
537
+ result = await this.analyzer.analyze(txs, segment, config);
538
+ return await this.checkForLoan(result, debtAccounts);
539
+ default:
540
+ throw new NotImplemented(`Cannot analyze yet type '${txs.type}' in ${this.constructor.name}.`);
541
+ }
542
+ }
543
+ /**
544
+ * Check if the resulting transactions needs to be recorded to loan account.
545
+ */
546
+ async checkForLoan(result, debtAccounts) {
547
+ if (!this.analyzer)
548
+ throw new Error('No analyzer. Internal error.');
549
+ for (const tx of result.transactions || []) {
550
+ for (const entry of tx.entries) {
551
+ if (entry.account in debtAccounts) {
552
+ // Find loan account if defined.
553
+ const balance = debtAccounts[entry.account];
554
+ const [loanReason, loanType, loanAsset] = balance.debtAddress.split('.');
555
+ const loanAccount = await this.analyzer.getAccount(loanReason, loanType, loanAsset);
556
+ if (balance.account === loanAccount) {
557
+ continue;
558
+ }
559
+ const accountBalance = this.analyzer.getBalance(balance.address) || 0;
560
+ const debtBalance = this.analyzer.getBalance(balance.debtAddress) || 0;
561
+ // Take more loan.
562
+ if (realNegative(accountBalance) && realNegative(entry.amount)) {
563
+ this.analyzer.revertBalance(entry);
564
+ const originalBalance = this.analyzer.getBalance(balance.address) || 0;
565
+ // Only partial loan needed.
566
+ if (realPositive(originalBalance)) {
567
+ const loanEntry = {
568
+ account: loanAccount || '0',
569
+ amount: -(-entry.amount - originalBalance),
570
+ description: entry.description
571
+ };
572
+ entry.amount = -originalBalance;
573
+ // Add tags if any.
574
+ loanEntry.description = mergeTags(loanEntry.description, await this.analyzer.getTagsForAddr(balance.debtAddress) || []);
575
+ tx.entries.push(loanEntry);
576
+ this.analyzer.applyBalance(entry);
577
+ this.analyzer.applyBalance(loanEntry);
578
+ }
579
+ else {
580
+ // Full loan needed.
581
+ entry.account = loanAccount || '0';
582
+ this.analyzer.applyBalance(entry);
583
+ }
584
+ }
585
+ // Pay back loan.
586
+ if (realNegative(debtBalance) && realPositive(entry.amount)) {
587
+ this.analyzer.revertBalance(entry);
588
+ // Getting more than full payment.
589
+ if (less(-debtBalance, entry.amount)) {
590
+ const loanEntry = {
591
+ account: loanAccount || '0',
592
+ amount: -debtBalance,
593
+ description: entry.description
594
+ };
595
+ entry.amount -= -debtBalance;
596
+ // Add tags if any.
597
+ loanEntry.description = mergeTags(loanEntry.description, await this.analyzer.getTagsForAddr(balance.debtAddress) || []);
598
+ tx.entries.push(loanEntry);
599
+ this.analyzer.applyBalance(entry);
600
+ this.analyzer.applyBalance(loanEntry);
601
+ }
602
+ else {
603
+ // Partial payment.
604
+ entry.account = loanAccount || '0';
605
+ this.analyzer.applyBalance(entry);
606
+ }
607
+ }
608
+ }
609
+ }
610
+ }
611
+ return result;
612
+ }
613
+ /**
614
+ * Dump analysis results.
615
+ * @param state
616
+ */
617
+ debugAnalysis(state) {
618
+ if (state.result !== undefined) {
619
+ Object.keys(state.result).forEach(segmentId => {
620
+ debug('ANALYSIS', `Analyzed ${segmentId}`);
621
+ if (state.result && segmentId in state.result) {
622
+ for (const result of state.result[segmentId]) {
623
+ debug('ANALYSIS', result.transfers);
624
+ }
625
+ }
626
+ });
627
+ }
628
+ }
629
+ /**
630
+ * Apply the result using the connector.
631
+ * @param state
632
+ * @param files
633
+ * @returns
634
+ */
635
+ async execution(process, state, files) {
636
+ const output = new TransactionApplyResults();
637
+ if (state.result) {
638
+ // Initialize all execution results.
639
+ for (const segmentId of Object.keys(state.result)) {
640
+ const result = state.result[segmentId];
641
+ for (const res of result) {
642
+ if (res.transactions) {
643
+ for (const tx of res.transactions) {
644
+ if (!tx.executionResult) {
645
+ tx.executionResult = 'not done';
646
+ }
647
+ }
648
+ }
649
+ }
650
+ }
651
+ // Apply everything segment by segment.
652
+ for (const segmentId of Object.keys(state.result)) {
653
+ debug('EXECUTION', `Execution of segment ${segmentId}`);
654
+ const result = state.result[segmentId];
655
+ for (const res of result) {
656
+ debug('EXECUTION', res.transactions);
657
+ const hasOld = await this.system.connector.resultExists(process.id, res);
658
+ if (hasOld) {
659
+ const allow = await this.UI.getBoolean(process.config, 'allowIdenticalTx', 'Allow creation of identical transactions that has been already created.');
660
+ if (!allow) {
661
+ for (const tx of res.transactions || []) {
662
+ tx.executionResult = 'duplicate';
663
+ output.duplicate(tx);
664
+ }
665
+ continue;
666
+ }
667
+ log(`Duplicate transaction created ${JSON.stringify(res.transactions)} since allowed in settings.`);
668
+ }
669
+ const applied = await this.system.connector.applyResult(process.id, res);
670
+ output.add(applied);
671
+ }
672
+ }
673
+ }
674
+ // Remove stock data.
675
+ this.analyzer = null;
676
+ return {
677
+ ...state,
678
+ output: output.toJSON(),
679
+ stage: 'executed'
680
+ };
681
+ }
682
+ /**
683
+ * Ask VAT from connector.
684
+ * @param time
685
+ * @param reason
686
+ * @param asset
687
+ * @param currency
688
+ */
689
+ async getVAT(time, transfer, currency) {
690
+ const connector = this.system.connector;
691
+ return connector.getVAT(time, transfer, currency);
692
+ }
693
+ /**
694
+ * Find the rate in the default currency for the asset.
695
+ * If there is information about rates inside the files, this function could be overridden and
696
+ * used for digging actual values. Those values can be collected during parse() call.
697
+ * @param time
698
+ * @param type
699
+ * @param asset
700
+ */
701
+ async getRate(time, type, asset, currency, exchange) {
702
+ if (!isTransactionImportConnector(this.system.connector)) {
703
+ throw new SystemError('Connector used is not a transaction import connector.');
704
+ }
705
+ return this.system.connector.getRate(time, type, asset, currency, exchange);
706
+ }
707
+ /**
708
+ * Remove transactions created.
709
+ */
710
+ async rollback(process, state) {
711
+ const success = await this.system.connector.rollback(process.id);
712
+ if (!success) {
713
+ throw new SystemError('Rollback failed.');
714
+ }
715
+ if (state.result) {
716
+ for (const segmentId of Object.keys(state.result)) {
717
+ const result = state.result[segmentId];
718
+ for (const res of result) {
719
+ if (res.transactions) {
720
+ for (const tx of res.transactions) {
721
+ tx.executionResult = 'reverted';
722
+ }
723
+ }
724
+ }
725
+ }
726
+ }
727
+ return {
728
+ ...state,
729
+ stage: 'rolledback'
730
+ };
731
+ }
732
+ }
733
+ //# sourceMappingURL=TransactionImportHandler.js.map