Skip to content

Commit

Permalink
[FIX] account_statement_import_online_gocardless: IBAN comparison
Browse files Browse the repository at this point in the history
It is possible that, when making the request to the requisitions endpoint,
the IBAN bank account comes with a lower alphanumeric string.
When comparing with the sanitized bank account (stored with upper) fails.

self.journal_id.bank_account_id.sanitized_acc_number == account_data["iban"]

to

self.journal_id.bank_account_id.sanitized_acc_number == account_data["iban"].upper()

Refactor method _gocardless_finish_requisition to be able to mock the requests made inside and create a unit test.
  • Loading branch information
ljsalvatierra-factorlibre committed Apr 26, 2024
1 parent 4a89d34 commit eaac361
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,36 @@ def action_check_gocardless_agreement(self):
# JS code expects here to return a plain link or nothing
return requisition_data["link"]

def _gocardless_request_requisition(self):
response = requests.get(
f"{GOCARDLESS_ENDPOINT}/requisitions/{self.gocardless_requisition_id}/",
headers=self._gocardless_get_headers(),
timeout=REQUESTS_TIMEOUT,
)
if response.status_code == 200:
return json.loads(response.text)
return {}

def _gocardless_request_account(self, account_id):
response = requests.get(
f"{GOCARDLESS_ENDPOINT}/accounts/{account_id}/",
headers=self._gocardless_get_headers(),
timeout=REQUESTS_TIMEOUT,
)
if response.status_code == 200:
return json.loads(response.text)
return {}

def _gocardless_request_agreement(self, agreement_id):
response = requests.get(
f"{GOCARDLESS_ENDPOINT}/agreements/enduser/" f"{agreement_id}/",
headers=self._gocardless_get_headers(),
timeout=REQUESTS_TIMEOUT,
)
if response.status_code == 200:
return json.loads(response.text)
return {}

def _gocardless_finish_requisition(self, dry=False):
"""Once the requisiton to the bank institution has been made, and this is called
from the controller assigned to the redirect URL, we check that the IBAN account
Expand All @@ -203,39 +233,25 @@ def _gocardless_finish_requisition(self, dry=False):
process, so no fail message is logged in chatter in this case.
"""
self.ensure_one()
requisition_response = requests.get(
f"{GOCARDLESS_ENDPOINT}/requisitions/{self.gocardless_requisition_id}/",
headers=self._gocardless_get_headers(),
timeout=REQUESTS_TIMEOUT,
)
requisition_data = json.loads(requisition_response.text)
requisition_data = self._gocardless_request_requisition()
accounts = requisition_data.get("accounts", [])
found_account = False
accounts_iban = []
for account_id in accounts:
account_response = requests.get(
f"{GOCARDLESS_ENDPOINT}/accounts/{account_id}/",
headers=self._gocardless_get_headers(),
timeout=REQUESTS_TIMEOUT,
)
if account_response.status_code == 200:
account_data = json.loads(account_response.text)
account_data = self._gocardless_request_account(account_id)
if account_data:
accounts_iban.append(account_data["iban"])
if (
self.journal_id.bank_account_id.sanitized_acc_number
== account_data["iban"]
== account_data["iban"].upper()
):
found_account = True
self.gocardless_account_id = account_data["id"]
break
if found_account:
agreement_response = requests.get(
f"{GOCARDLESS_ENDPOINT}/agreements/enduser/"
f"{requisition_data['agreement']}/",
headers=self._gocardless_get_headers(),
timeout=REQUESTS_TIMEOUT,
agreement_data = self._gocardless_request_agreement(
requisition_data["agreement"]
)
agreement_data = json.loads(agreement_response.text)
self.gocardless_requisition_expiration = datetime.strptime(
agreement_data["accepted"], "%Y-%m-%dT%H:%M:%S.%fZ"
) + relativedelta(days=agreement_data["access_valid_for_days"])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ def setUpClass(cls):
cls.now = fields.Datetime.now()
cls.currency_eur = cls.env.ref("base.EUR")
cls.currency_eur.write({"active": True})
bank_account = cls.env["res.partner.bank"].create(
{
"acc_number": "NL77ABNA0574908765",
"partner_id": cls.env.ref("base.main_partner").id,
"company_id": cls.env.ref("base.main_company").id,
"bank_id": cls.env.ref("base.res_bank_1").id,
}
)
cls.journal = cls.env["account.journal"].create(
{
"name": "GoCardless Bank Test",
Expand All @@ -29,6 +37,7 @@ def setUpClass(cls):
"currency_id": cls.currency_eur.id,
"bank_statements_source": "online",
"online_bank_statement_provider": "gocardless",
"bank_account_id": bank_account.id,
}
)
cls.provider = cls.journal.online_bank_statement_provider_id
Expand Down Expand Up @@ -77,6 +86,31 @@ def setUpClass(cls):
_provider_class + "._gocardless_request_transactions",
return_value=cls.return_value,
)
cls.request_requisition_value = {
"accounts": ["ACCOUNT-ID-1"],
"agreement": "TEST-AGREEMENT-ID",
}
cls.mock_requisition = lambda cls: mock.patch(
_provider_class + "._gocardless_request_requisition",
return_value=cls.request_requisition_value,
)
cls.request_account_value = {
"id": "ACCOUNT-ID-1",
"iban": "nl77abna0574908765",
}
cls.mock_account = lambda cls: mock.patch(
_provider_class + "._gocardless_request_account",
return_value=cls.request_account_value,
)
cls.request_agreement_value = {
"id": "TEST-AGREEMENT-ID",
"accepted": cls.now.strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
"access_valid_for_days": 30,
}
cls.mock_agreement = lambda cls: mock.patch(
_provider_class + "._gocardless_request_agreement",
return_value=cls.request_agreement_value,
)

def test_mocked_gocardless(self):
vals = {
Expand All @@ -100,3 +134,8 @@ def test_mocked_gocardless(self):
lines = statements.line_ids.sorted(lambda x: x.date)
self.assertEqual(len(lines), 2)
self.assertEqual(lines.mapped("amount"), [45.0, -15.0])

def test_provider_gocardless_finish_requisition(self):
with self.mock_requisition(), self.mock_account(), self.mock_agreement():
res = self.provider._gocardless_finish_requisition(dry=True)
self.assertTrue(res, "Bank account not found!")

0 comments on commit eaac361

Please sign in to comment.