Implement getting bank account details

This commit is contained in:
Mark Veidemanis 2023-03-08 17:04:47 +00:00
parent 144e048d5f
commit c0dc41a63a
Signed by: m
GPG Key ID: 5ACFCEED46C0904F
5 changed files with 145 additions and 6 deletions

View File

@ -87,4 +87,10 @@ urlpatterns = [
aggregators.ReqDelete.as_view(), aggregators.ReqDelete.as_view(),
name="req_delete", name="req_delete",
), ),
# Requisition info
path(
"aggs/<str:type>/info/<str:pk>/<str:req_id>/",
aggregators.ReqInfo.as_view(),
name="req_info",
),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

View File

@ -104,3 +104,78 @@ class NordigenClient(BaseClient):
path, schema="RequisitionDelete", http_method="delete" path, schema="RequisitionDelete", http_method="delete"
) )
return response return response
async def get_requisition(self, requisition):
"""
Get a list of accounts for a requisition.
:param requisition: requisition ID"""
path = f"requisitions/{requisition}"
response = await self.call(path, schema="Requisition")
return response
# def get_ownernames(self):
# """
# Get list of supplementary owner names.
# """
# ownernames = loads(settings.Nordigen.OwnerNames)
# return ownernames
async def get_account(self, account_id):
"""
Get details of an account.
:param requisition: requisition ID"""
path = f"accounts/{account_id}/details"
response = await self.call(path, schema="AccountDetails")
if "account" not in response:
return False
parsed = response["account"]
if "bban" in parsed and parsed["currency"] == "GBP":
sort_code = parsed["bban"][0:6]
account_number = parsed["bban"][6:]
# if "ownerName" not in parsed:
# ownernames = self.get_ownernames()
# if account_id in ownernames:
# parsed["ownerName"] = ownernames[account_id]
# else:
# return False
# recipient = parsed["ownerName"]
del parsed["bban"]
if "iban" in parsed:
del parsed["iban"]
sort_code = "-".join(list(map("".join, zip(*[iter(sort_code)] * 2))))
parsed["sort_code"] = sort_code
parsed["number"] = account_number
parsed["recipient"] = "TODO"
# Let's add the account ID so we can reference it later
parsed["account_id"] = account_id
print("PARSED", parsed)
return parsed
async def get_all_account_info(self, requisition=None):
print("GET ALL ACCOU T INFO", requisition)
to_return = {}
if not requisition:
raise NotImplementedError
# requisitions = await self.get_requisitions()
else:
requisitions = [await self.get_requisition(requisition)]
print("REQUISITIONS", requisitions)
print("REQUISITIONS", requisitions)
for req in requisitions:
print("REQ ITER", req)
accounts = req["accounts"]
print("ACCOUNTS", accounts)
for account_id in accounts:
account_info = await self.get_account(account_id)
if not account_info:
continue
if req["institution_id"] in to_return:
to_return[req["institution_id"]].append(account_info)
else:
to_return[req["institution_id"]] = [account_info]
return to_return

View File

@ -43,7 +43,7 @@
</span> </span>
</button> </button>
{% if type == 'page' %} {% if type == 'page' %}
<a href="{# url 'aggregator_read' type=type pk=item.id #}"><button <a href="{% url 'req_info' type=type pk=pk req_id=item.id %}"><button
class="button"> class="button">
<span class="icon-text"> <span class="icon-text">
<span class="icon"> <span class="icon">
@ -55,7 +55,7 @@
{% else %} {% else %}
<button <button
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}' hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
hx-get="{# url 'aggregator_info' type=type pk=item.id #}" hx-get="{% url 'req_info' type=type pk=pk req_id=item.id %}"
hx-trigger="click" hx-trigger="click"
hx-target="#{{ type }}s-here" hx-target="#{{ type }}s-here"
hx-swap="innerHTML" hx-swap="innerHTML"

View File

@ -0,0 +1,28 @@
{% include 'mixins/partials/notify.html' %}
<h1 class="title">{{ title_singular }} info</h1>
{% for key, item in object.items %}
<h1 class="title is-4">Bank: {{ key }}</h1>
{% for account in item %}
<table class="table is-fullwidth is-hoverable box">
<thead>
<th>attribute</th>
<th>value</th>
</thead>
<tbody>
{% for key_i, item_i in account.items %}
<tr>
<th>{{ key_i }}</th>
<td>
{% if item_i is not None %}
{{ item_i }}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
<hr/>
{% endfor %}

View File

@ -3,7 +3,13 @@ import asyncio
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse from django.http import HttpResponse
from django.views import View from django.views import View
from mixins.views import ObjectCreate, ObjectDelete, ObjectList, ObjectUpdate from mixins.views import (
ObjectCreate,
ObjectDelete,
ObjectList,
ObjectRead,
ObjectUpdate,
)
from two_factor.views.mixins import OTPRequiredMixin from two_factor.views.mixins import OTPRequiredMixin
from core.clients.aggregators.nordigen import NordigenClient from core.clients.aggregators.nordigen import NordigenClient
@ -175,12 +181,9 @@ class AggregatorLinkBank(LoginRequiredMixin, OTPRequiredMixin, View):
run = synchronize_async_helper(NordigenClient(aggregator)) run = synchronize_async_helper(NordigenClient(aggregator))
auth_url = synchronize_async_helper(run.build_link(bank)) auth_url = synchronize_async_helper(run.build_link(bank))
# Redirect to auth url
print("AUTH URL", auth_url)
# Create a blank response # Create a blank response
response = HttpResponse() response = HttpResponse()
response["HX-Redirect"] = auth_url response["HX-Redirect"] = auth_url
# return redirect(auth_url)
return response return response
@ -207,6 +210,33 @@ class ReqDelete(LoginRequiredMixin, OTPRequiredMixin, View):
return response return response
class ReqInfo(LoginRequiredMixin, OTPRequiredMixin, ObjectRead):
context_object_name_singular = "requisition"
context_object_name = "requisitions"
detail_template = "partials/aggregator-req-info.html"
def get_object(self, **kwargs):
pk = kwargs.get("pk")
req_id = kwargs.get("req_id")
try:
aggregator = Aggregator.get_by_id(pk, self.request.user)
except Aggregator.DoesNotExist:
message = "Aggregator does not exist"
message_class = "danger"
context = {
"message": message,
"message_class": message_class,
"window_content": self.window_content,
}
return self.render_to_response(context)
run = synchronize_async_helper(NordigenClient(aggregator))
req = synchronize_async_helper(run.get_all_account_info(req_id))
print("REQ KEYS", req.keys())
self.extra_context = {"pretty": list(req.keys())}
return req
class AggregatorList(LoginRequiredMixin, OTPRequiredMixin, ObjectList): class AggregatorList(LoginRequiredMixin, OTPRequiredMixin, ObjectList):
list_template = "partials/aggregator-list.html" list_template = "partials/aggregator-list.html"
model = Aggregator model = Aggregator