diff --git a/account_bank_statement_import_online_paypal/models/online_bank_statement_provider_paypal.py b/account_bank_statement_import_online_paypal/models/online_bank_statement_provider_paypal.py index 96bb158..d4e10f9 100644 --- a/account_bank_statement_import_online_paypal/models/online_bank_statement_provider_paypal.py +++ b/account_bank_statement_import_online_paypal/models/online_bank_statement_provider_paypal.py @@ -1,5 +1,5 @@ -# Copyright 2019 Brainbean Apps (https://brainbeanapps.com) -# Copyright 2019 Dataplug (https://dataplug.io) +# Copyright 2019-2020 Brainbean Apps (https://brainbeanapps.com) +# Copyright 2019-2020 Dataplug (https://dataplug.io) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from base64 import b64encode @@ -212,7 +212,15 @@ class OnlineBankStatementProviderPayPal(models.Model): date_until ) if not transactions: - return None + balance = self._paypal_get_balance( + token, + currency, + date_since + ) + return [], { + 'balance_start': balance, + 'balance_end_real': balance, + } # Normalize transactions, sort by date, and get lines transactions = list(sorted( @@ -365,6 +373,20 @@ class OnlineBankStatementProviderPayPal(models.Model): )) return data['access_token'] + @api.multi + def _paypal_get_balance(self, token, currency, as_of_timestamp): + self.ensure_one() + url = (self.api_base or PAYPAL_API_BASE) \ + + '/v1/reporting/balances?currency_code=%s&as_of_time=%s' % ( + currency, + as_of_timestamp.isoformat() + 'Z', + ) + data = self._paypal_retrieve(url, token) + available_balance = data['balances'][0].get('available_balance') + if not available_balance: + return Decimal() + return Decimal(available_balance['value']) + @api.multi def _paypal_get_transaction(self, token, transaction_id, timestamp): self.ensure_one() diff --git a/account_bank_statement_import_online_paypal/tests/test_account_bank_statement_import_online_paypal.py b/account_bank_statement_import_online_paypal/tests/test_account_bank_statement_import_online_paypal.py index 792eb25..30f5092 100644 --- a/account_bank_statement_import_online_paypal/tests/test_account_bank_statement_import_online_paypal.py +++ b/account_bank_statement_import_online_paypal/tests/test_account_bank_statement_import_online_paypal.py @@ -194,16 +194,39 @@ class TestAccountBankAccountStatementImportOnlinePayPal( }) provider = journal.online_bank_statement_provider_id - mocked_response = UrlopenRetValMock("""{ + mocked_response_1 = UrlopenRetValMock("""{ "debug_id": "eec890ebd5798", "details": "xxxxxx", "links": "xxxxxx", "message": "Data for the given start date is not available.", "name": "INVALID_REQUEST" }""", throw=True) + mocked_response_2 = UrlopenRetValMock("""{ + "balances": [ + { + "currency": "EUR", + "primary": true, + "total_balance": { + "currency_code": "EUR", + "value": "0.75" + }, + "available_balance": { + "currency_code": "EUR", + "value": "0.75" + }, + "withheld_balance": { + "currency_code": "EUR", + "value": "0.00" + } + } + ], + "account_id": "1234567890", + "as_of_time": "2019-08-01T00:00:00+0000", + "last_refresh_time": "2019-08-01T00:00:00+0000" +}""") with mock.patch( _provider_class + '._paypal_urlopen', - return_value=mocked_response, + side_effect=[mocked_response_1, mocked_response_2], ), self.mock_token(): data = provider.with_context( test_account_bank_statement_import_online_paypal_monday=True, @@ -212,7 +235,10 @@ class TestAccountBankAccountStatementImportOnlinePayPal( self.now, ) - self.assertIsNone(data) + self.assertEqual(data, ([], { + 'balance_start': 0.75, + 'balance_end_real': 0.75, + })) def test_error_handling_1(self): journal = self.AccountJournal.create({ @@ -269,7 +295,7 @@ class TestAccountBankAccountStatementImportOnlinePayPal( }) provider = journal.online_bank_statement_provider_id - mocked_response = json.loads("""{ + mocked_response_1 = json.loads("""{ "transaction_details": [], "account_number": "1234567890", "start_date": "2019-08-01T00:00:00+0000", @@ -278,17 +304,43 @@ class TestAccountBankAccountStatementImportOnlinePayPal( "page": 1, "total_items": 0, "total_pages": 0 +}""", parse_float=Decimal) + mocked_response_2 = json.loads("""{ + "balances": [ + { + "currency": "EUR", + "primary": true, + "total_balance": { + "currency_code": "EUR", + "value": "0.75" + }, + "available_balance": { + "currency_code": "EUR", + "value": "0.75" + }, + "withheld_balance": { + "currency_code": "EUR", + "value": "0.00" + } + } + ], + "account_id": "1234567890", + "as_of_time": "2019-08-01T00:00:00+0000", + "last_refresh_time": "2019-08-01T00:00:00+0000" }""", parse_float=Decimal) with mock.patch( _provider_class + '._paypal_retrieve', - return_value=mocked_response, + side_effect=[mocked_response_1, mocked_response_2], ), self.mock_token(): data = provider._obtain_statement_data( self.now - relativedelta(hours=1), self.now, ) - self.assertIsNone(data) + self.assertEqual(data, ([], { + 'balance_start': 0.75, + 'balance_end_real': 0.75, + })) def test_ancient_pull(self): journal = self.AccountJournal.create({