You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

552 lines
16 KiB

  1. # Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
  2. # Copyright 2019 Dataplug (https://dataplug.io)
  3. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
  4. from datetime import datetime
  5. from dateutil.relativedelta import relativedelta
  6. from decimal import Decimal
  7. import json
  8. from unittest import mock
  9. from odoo.tests import common
  10. from odoo import fields
  11. _module_ns = 'odoo.addons.account_bank_statement_import_online_transferwise'
  12. _provider_class = (
  13. _module_ns
  14. + '.models.online_bank_statement_provider_transferwise'
  15. + '.OnlineBankStatementProviderTransferwise'
  16. )
  17. class TestAccountBankAccountStatementImportOnlineTransferwise(
  18. common.TransactionCase
  19. ):
  20. def setUp(self):
  21. super().setUp()
  22. self.now = fields.Datetime.now()
  23. self.currency_eur = self.env.ref('base.EUR')
  24. self.currency_usd = self.env.ref('base.USD')
  25. self.AccountJournal = self.env['account.journal']
  26. self.OnlineBankStatementProvider = self.env[
  27. 'online.bank.statement.provider'
  28. ]
  29. self.AccountBankStatement = self.env['account.bank.statement']
  30. self.AccountBankStatementLine = self.env['account.bank.statement.line']
  31. Provider = self.OnlineBankStatementProvider
  32. self.transferwise_parse_transaction = lambda payload: (
  33. Provider._transferwise_transaction_to_lines(
  34. Provider._transferwise_preparse_transaction(
  35. json.loads(
  36. payload,
  37. parse_float=Decimal,
  38. )
  39. )
  40. )
  41. )
  42. def test_values_transferwise_profile(self):
  43. mocked_response = json.loads(
  44. """[
  45. {
  46. "id": 1234567890,
  47. "type": "personal",
  48. "details": {
  49. "firstName": "Alexey",
  50. "lastName": "Pelykh"
  51. }
  52. },
  53. {
  54. "id": 1234567891,
  55. "type": "business",
  56. "details": {
  57. "name": "Brainbean Apps OÜ"
  58. }
  59. }
  60. ]""", parse_float=Decimal)
  61. values_transferwise_profile = []
  62. with mock.patch(
  63. _provider_class + '._transferwise_retrieve',
  64. return_value=mocked_response,
  65. ):
  66. values_transferwise_profile = (
  67. self.OnlineBankStatementProvider.with_context({
  68. 'api_base': 'https://example.com',
  69. 'api_key': 'dummy',
  70. }).values_transferwise_profile()
  71. )
  72. self.assertEqual(
  73. values_transferwise_profile,
  74. [
  75. ('1234567890', 'Alexey Pelykh (personal)'),
  76. ('1234567891', 'Brainbean Apps OÜ'),
  77. ]
  78. )
  79. def test_pull(self):
  80. journal = self.AccountJournal.create({
  81. 'name': 'Bank',
  82. 'type': 'bank',
  83. 'code': 'BANK',
  84. 'currency_id': self.currency_eur.id,
  85. 'bank_statements_source': 'online',
  86. 'online_bank_statement_provider': 'transferwise',
  87. })
  88. provider = journal.online_bank_statement_provider_id
  89. provider.origin = '1234567891'
  90. def mock_response(url, api_key):
  91. if '/borderless-accounts?profileId=1234567891' in url:
  92. payload = """[
  93. {
  94. "id": 42,
  95. "balances": [
  96. {
  97. "currency": "EUR"
  98. }
  99. ]
  100. }
  101. ]"""
  102. elif '/borderless-accounts/42/statement.json' in url:
  103. payload = """{
  104. "transactions": [],
  105. "endOfStatementBalance": {
  106. "value": 42.00,
  107. "currency": "EUR"
  108. }
  109. }"""
  110. return json.loads(payload, parse_float=Decimal)
  111. with mock.patch(
  112. _provider_class + '._transferwise_retrieve',
  113. side_effect=mock_response,
  114. ):
  115. data = provider._obtain_statement_data(
  116. self.now - relativedelta(hours=1),
  117. self.now,
  118. )
  119. self.assertEqual(len(data[0]), 0)
  120. self.assertEqual(data[1]['balance_start'], 42.0)
  121. self.assertEqual(data[1]['balance_end_real'], 42.0)
  122. def test_transaction_parse_1(self):
  123. lines = self.transferwise_parse_transaction("""{
  124. "type": "CREDIT",
  125. "date": "2000-01-01T00:00:00.000Z",
  126. "amount": {
  127. "value": 0.42,
  128. "currency": "EUR"
  129. },
  130. "totalFees": {
  131. "value": 0.00,
  132. "currency": "EUR"
  133. },
  134. "details": {
  135. "type": "DEPOSIT",
  136. "description": "Received money from SENDER with reference REF-XYZ",
  137. "senderName": "SENDER",
  138. "senderAccount": "XX00 0000 0000 0000",
  139. "paymentReference": "REF-XYZ"
  140. },
  141. "exchangeDetails": null,
  142. "runningBalance": {
  143. "value": 0.42,
  144. "currency": "EUR"
  145. },
  146. "referenceNumber": "TRANSFER-123456789"
  147. }""")
  148. self.assertEqual(len(lines), 1)
  149. self.assertEqual(lines[0], {
  150. 'date': datetime(2000, 1, 1),
  151. 'amount': '0.42',
  152. 'name': 'REF-XYZ',
  153. 'note': (
  154. 'TRANSFER-123456789: Received money from SENDER with reference'
  155. ' REF-XYZ'
  156. ),
  157. 'partner_name': 'SENDER',
  158. 'account_number': 'XX00 0000 0000 0000',
  159. 'unique_import_id': 'CREDIT-TRANSFER-123456789-946684800',
  160. })
  161. def test_transaction_parse_2(self):
  162. lines = self.transferwise_parse_transaction("""{
  163. "type": "DEBIT",
  164. "date": "2000-01-01T00:00:00.000Z",
  165. "amount": {
  166. "value": -200.60,
  167. "currency": "EUR"
  168. },
  169. "totalFees": {
  170. "value": 0.60,
  171. "currency": "EUR"
  172. },
  173. "details": {
  174. "type": "TRANSFER",
  175. "description": "Sent money to John Doe",
  176. "recipient": {
  177. "name": "John Doe",
  178. "bankAccount": "XX00 0000 0000 0000"
  179. },
  180. "paymentReference": "INVOICE 42-01"
  181. },
  182. "exchangeDetails": null,
  183. "runningBalance": {
  184. "value": 100.42,
  185. "currency": "EUR"
  186. },
  187. "referenceNumber": "TRANSFER-123456789"
  188. }""")
  189. self.assertEqual(len(lines), 2)
  190. self.assertEqual(lines[0], {
  191. 'date': datetime(2000, 1, 1),
  192. 'amount': '-200.00',
  193. 'name': 'INVOICE 42-01',
  194. 'note': 'TRANSFER-123456789: Sent money to John Doe',
  195. 'partner_name': 'John Doe',
  196. 'account_number': 'XX00 0000 0000 0000',
  197. 'unique_import_id': 'DEBIT-TRANSFER-123456789-946684800',
  198. })
  199. self.assertEqual(lines[1], {
  200. 'date': datetime(2000, 1, 1),
  201. 'amount': '-0.60',
  202. 'name': 'Fee for TRANSFER-123456789',
  203. 'note': 'Transaction fee for TRANSFER-123456789',
  204. 'partner_name': 'TransferWise',
  205. 'unique_import_id': 'DEBIT-TRANSFER-123456789-946684800-FEE',
  206. })
  207. def test_transaction_parse_3(self):
  208. lines = self.transferwise_parse_transaction("""{
  209. "type": "DEBIT",
  210. "date": "2000-01-01T00:00:00.000Z",
  211. "amount": {
  212. "value": -123.45,
  213. "currency": "USD"
  214. },
  215. "totalFees": {
  216. "value": 0.00,
  217. "currency": "USD"
  218. },
  219. "details": {
  220. "type": "CARD",
  221. "description":
  222. "Card transaction of 1234.56 USD issued by Paypal *XX CITY",
  223. "amount": {
  224. "value": 1234.56,
  225. "currency": "USD"
  226. },
  227. "category": "Professional Services not elsewh",
  228. "merchant": {
  229. "name": "Paypal *XX",
  230. "firstLine": null,
  231. "postCode": "12345",
  232. "city": "CITY",
  233. "state": null,
  234. "country": "GB",
  235. "category": "Professional Services not elsewh"
  236. }
  237. },
  238. "exchangeDetails": null,
  239. "runningBalance": {
  240. "value": 0.00,
  241. "currency": "USD"
  242. },
  243. "referenceNumber": "CARD-123456789"
  244. }""")
  245. self.assertEqual(len(lines), 1)
  246. self.assertEqual(lines[0], {
  247. 'date': datetime(2000, 1, 1),
  248. 'amount': '-123.45',
  249. 'name': (
  250. 'Card transaction of 1234.56 USD issued by Paypal *XX CITY'
  251. ),
  252. 'note': (
  253. 'CARD-123456789: Card transaction of 1234.56 USD issued by '
  254. 'Paypal *XX CITY'
  255. ),
  256. 'partner_name': 'Paypal *XX',
  257. 'unique_import_id': 'DEBIT-CARD-123456789-946684800',
  258. })
  259. def test_transaction_parse_4(self):
  260. lines = self.transferwise_parse_transaction("""{
  261. "type": "DEBIT",
  262. "date": "2000-01-01T00:00:00.000Z",
  263. "amount": {
  264. "value": -456.78,
  265. "currency": "EUR"
  266. },
  267. "totalFees": {
  268. "value": 1.23,
  269. "currency": "EUR"
  270. },
  271. "details": {
  272. "type": "CARD",
  273. "description":
  274. "Card transaction of 1234.56 USD issued by Paypal *XX CITY",
  275. "amount": {
  276. "value": 1234.56,
  277. "currency": "USD"
  278. },
  279. "category": "Professional Services not elsewh",
  280. "merchant": {
  281. "name": "Paypal *XX",
  282. "firstLine": null,
  283. "postCode": "12345",
  284. "city": "CITY",
  285. "state": null,
  286. "country": "GB",
  287. "category": "Professional Services not elsewh"
  288. }
  289. },
  290. "exchangeDetails": {
  291. "toAmount": {
  292. "value": 567.89,
  293. "currency": "USD"
  294. },
  295. "fromAmount": {
  296. "value": 456.78,
  297. "currency": "EUR"
  298. },
  299. "rate": 1.12260
  300. },
  301. "runningBalance": {
  302. "value": 0.00,
  303. "currency": "EUR"
  304. },
  305. "referenceNumber": "CARD-123456789"
  306. }""")
  307. self.assertEqual(len(lines), 2)
  308. self.assertEqual(lines[0], {
  309. 'date': datetime(2000, 1, 1),
  310. 'amount': '-455.55',
  311. 'name': (
  312. 'Card transaction of 1234.56 USD issued by Paypal *XX CITY'
  313. ),
  314. 'note': (
  315. 'CARD-123456789: Card transaction of 1234.56 USD issued by'
  316. ' Paypal *XX CITY'
  317. ),
  318. 'partner_name': 'Paypal *XX',
  319. 'unique_import_id': 'DEBIT-CARD-123456789-946684800',
  320. 'amount_currency': '-567.89',
  321. 'currency_id': self.currency_usd.id,
  322. })
  323. self.assertEqual(lines[1], {
  324. 'date': datetime(2000, 1, 1),
  325. 'amount': '-1.23',
  326. 'name': 'Fee for CARD-123456789',
  327. 'note': 'Transaction fee for CARD-123456789',
  328. 'partner_name': 'TransferWise',
  329. 'unique_import_id': 'DEBIT-CARD-123456789-946684800-FEE',
  330. })
  331. def test_transaction_parse_5(self):
  332. lines = self.transferwise_parse_transaction("""{
  333. "type": "DEBIT",
  334. "date": "2000-01-01T00:00:00.000Z",
  335. "amount": {
  336. "value": -270.55,
  337. "currency": "EUR"
  338. },
  339. "totalFees": {
  340. "value": 5.21,
  341. "currency": "EUR"
  342. },
  343. "details": {
  344. "type": "TRANSFER",
  345. "description": "Sent money to Jane Doe",
  346. "recipient": {
  347. "name": "Jane Doe",
  348. "bankAccount": "(ADBCDEF) 0000000000000000"
  349. },
  350. "paymentReference": "Invoice A from DD MMM YYYY"
  351. },
  352. "exchangeDetails": {
  353. "toAmount": {
  354. "value": 297.00,
  355. "currency": "USD"
  356. },
  357. "fromAmount": {
  358. "value": 265.34,
  359. "currency": "EUR"
  360. },
  361. "rate": 1.11930
  362. },
  363. "runningBalance": {
  364. "value": 2360.43,
  365. "currency": "EUR"
  366. },
  367. "referenceNumber": "TRANSFER-123456789"
  368. }""")
  369. self.assertEqual(len(lines), 2)
  370. self.assertEqual(lines[0], {
  371. 'date': datetime(2000, 1, 1),
  372. 'name': 'Invoice A from DD MMM YYYY',
  373. 'note': 'TRANSFER-123456789: Sent money to Jane Doe',
  374. 'partner_name': 'Jane Doe',
  375. 'account_number': '(ADBCDEF) 0000000000000000',
  376. 'amount': '-265.34',
  377. 'amount_currency': '-297.00',
  378. 'currency_id': self.currency_usd.id,
  379. 'unique_import_id': 'DEBIT-TRANSFER-123456789-946684800',
  380. })
  381. self.assertEqual(lines[1], {
  382. 'date': datetime(2000, 1, 1),
  383. 'name': 'Fee for TRANSFER-123456789',
  384. 'note': 'Transaction fee for TRANSFER-123456789',
  385. 'partner_name': 'TransferWise',
  386. 'amount': '-5.21',
  387. 'unique_import_id': 'DEBIT-TRANSFER-123456789-946684800-FEE',
  388. })
  389. def test_transaction_parse_6(self):
  390. lines = self.transferwise_parse_transaction("""{
  391. "type": "CREDIT",
  392. "date": "2000-01-01T00:00:00.000Z",
  393. "amount": {
  394. "value": 5000.00,
  395. "currency": "EUR"
  396. },
  397. "totalFees": {
  398. "value": 0.00,
  399. "currency": "EUR"
  400. },
  401. "details": {
  402. "type": "MONEY_ADDED",
  403. "description": "Topped up balance"
  404. },
  405. "exchangeDetails": null,
  406. "runningBalance": {
  407. "value": 7071.13,
  408. "currency": "EUR"
  409. },
  410. "referenceNumber": "TRANSFER-123456789"
  411. }""")
  412. self.assertEqual(len(lines), 1)
  413. self.assertEqual(lines[0], {
  414. 'date': datetime(2000, 1, 1),
  415. 'name': 'Topped up balance',
  416. 'note': 'TRANSFER-123456789: Topped up balance',
  417. 'amount': '5000.00',
  418. 'unique_import_id': 'CREDIT-TRANSFER-123456789-946684800',
  419. })
  420. def test_transaction_parse_7(self):
  421. lines = self.transferwise_parse_transaction("""{
  422. "type": "CREDIT",
  423. "date": "2000-01-01T00:00:00.000Z",
  424. "amount": {
  425. "value": 6.93,
  426. "currency": "EUR"
  427. },
  428. "totalFees": {
  429. "value": 0.00,
  430. "currency": "EUR"
  431. },
  432. "details": {
  433. "type": "CONVERSION",
  434. "description": "Converted 7.93 USD to 6.93 EUR",
  435. "sourceAmount": {
  436. "value": 7.93,
  437. "currency": "USD"
  438. },
  439. "targetAmount": {
  440. "value": 6.93,
  441. "currency": "EUR"
  442. },
  443. "rate": 0.87944162
  444. },
  445. "exchangeDetails": {
  446. "toAmount": {
  447. "value": 6.93,
  448. "currency": "EUR"
  449. },
  450. "fromAmount": {
  451. "value": 7.93,
  452. "currency": "USD"
  453. },
  454. "rate": 0.87944
  455. },
  456. "runningBalance": {
  457. "value": 255.00,
  458. "currency": "EUR"
  459. },
  460. "referenceNumber": "BALANCE-123456789"
  461. }""")
  462. self.assertEqual(len(lines), 1)
  463. self.assertEqual(lines[0], {
  464. 'date': datetime(2000, 1, 1),
  465. 'name': 'Converted 7.93 USD to 6.93 EUR',
  466. 'note': 'BALANCE-123456789: Converted 7.93 USD to 6.93 EUR',
  467. 'amount': '6.93',
  468. 'amount_currency': '7.93',
  469. 'currency_id': self.currency_usd.id,
  470. 'unique_import_id': 'CREDIT-BALANCE-123456789-946684800',
  471. })
  472. def test_transaction_parse_8(self):
  473. lines = self.transferwise_parse_transaction("""{
  474. "type": "DEBIT",
  475. "date": "2000-01-01T00:00:00.000Z",
  476. "amount": {
  477. "value": -7.93,
  478. "currency": "USD"
  479. },
  480. "totalFees": {
  481. "value": 0.05,
  482. "currency": "USD"
  483. },
  484. "details": {
  485. "type": "CONVERSION",
  486. "description": "Converted 7.93 USD to 6.93 EUR",
  487. "sourceAmount": {
  488. "value": 7.93,
  489. "currency": "USD"
  490. },
  491. "targetAmount": {
  492. "value": 6.93,
  493. "currency": "EUR"
  494. },
  495. "rate": 0.87944162
  496. },
  497. "exchangeDetails": {
  498. "toAmount": {
  499. "value": 6.93,
  500. "currency": "EUR"
  501. },
  502. "fromAmount": {
  503. "value": 7.93,
  504. "currency": "USD"
  505. },
  506. "rate": 0.87944
  507. },
  508. "runningBalance": {
  509. "value": 0.00,
  510. "currency": "USD"
  511. },
  512. "referenceNumber": "BALANCE-123456789"
  513. }""")
  514. self.assertEqual(len(lines), 2)
  515. self.assertEqual(lines[0], {
  516. 'date': datetime(2000, 1, 1),
  517. 'name': 'Converted 7.93 USD to 6.93 EUR',
  518. 'note': 'BALANCE-123456789: Converted 7.93 USD to 6.93 EUR',
  519. 'amount': '-7.88',
  520. 'amount_currency': '-6.93',
  521. 'currency_id': self.currency_eur.id,
  522. 'unique_import_id': 'DEBIT-BALANCE-123456789-946684800',
  523. })
  524. self.assertEqual(lines[1], {
  525. 'date': datetime(2000, 1, 1),
  526. 'name': 'Fee for BALANCE-123456789',
  527. 'note': 'Transaction fee for BALANCE-123456789',
  528. 'amount': '-0.05',
  529. 'partner_name': 'TransferWise',
  530. 'unique_import_id': 'DEBIT-BALANCE-123456789-946684800-FEE',
  531. })