events updated
This commit is contained in:
parent
b8cebd9af4
commit
5223f36da7
|
|
@ -19,6 +19,7 @@ from api_validations.core_response import AlchemyJsonResponse
|
|||
|
||||
|
||||
class EventBindOccupantEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "UPDATE"
|
||||
__event_keys__ = {
|
||||
"5702f0a9-fe8f-4aae-922e-6e04b497ef6a": "bind_events_occupant_super_user",
|
||||
|
|
@ -28,11 +28,10 @@ class Config:
|
|||
"/authentication/create_password",
|
||||
"/authentication/reset_password",
|
||||
"/authentication/forgot",
|
||||
"/authentication/avatar",
|
||||
"/authentication/valid",
|
||||
"/api/Contact/Us/current_date",
|
||||
]
|
||||
NOT_SECURE_PATHS = ["/access/endpoints/available", "/validations/endpoint"]
|
||||
NOT_SECURE_PATHS = ["/access/endpoints/available", "/validations/endpoint", "/authentication/avatar"]
|
||||
|
||||
APP_NAME = "evyos-web-api-gateway"
|
||||
TITLE = "WAG API Web Api Gateway"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from api_events.events.address.address import (
|
|||
AddressPostCodeUpdateEventMethod,
|
||||
AddressPostCodeListEventMethod,
|
||||
)
|
||||
from api_events.events.authentication import (
|
||||
from api_events.events.application.authentication import (
|
||||
AuthenticationLoginEventMethod,
|
||||
AuthenticationSelectEventMethod,
|
||||
AuthenticationCheckTokenEventMethod,
|
||||
|
|
@ -143,7 +143,7 @@ from api_events.events.decision_book.project_decision_book_items import (
|
|||
BuildDecisionBookProjectItemsCreateEventMethod,
|
||||
BuildDecisionBookProjectItemsListEventMethod,
|
||||
)
|
||||
from api_events.events.events.events_bind_events import (
|
||||
from a_project_files.later_use_codes.events_bind_events import (
|
||||
EventBindOccupantEventMethod,
|
||||
EventBindEmployeeEventMethod,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import datetime
|
||||
import json
|
||||
import typing
|
||||
from typing import Union
|
||||
|
||||
import arrow
|
||||
from fastapi import status
|
||||
from fastapi.requests import Request
|
||||
from fastapi.exceptions import HTTPException
|
||||
|
|
@ -116,9 +118,11 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
def authentication_select_company_or_occupant_type(
|
||||
cls,
|
||||
request: Request,
|
||||
data,
|
||||
token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
data: Union[EmployeeSelection, OccupantSelection],
|
||||
token_dict: Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
from api_objects import OccupantToken, CompanyToken
|
||||
|
||||
if isinstance(token_dict, EmployeeTokenObject):
|
||||
if data.company_uu_id not in token_dict.companies_uu_id_list:
|
||||
return JSONResponse(
|
||||
|
|
@ -141,7 +145,6 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
duties.id
|
||||
for duties in Duties.filter_all(
|
||||
Duties.company_id == selected_company.id,
|
||||
Duties.department_id.in_(department_ids),
|
||||
).data
|
||||
]
|
||||
staff_ids = [
|
||||
|
|
@ -154,7 +157,6 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
Employees.people_id == token_dict.person_id,
|
||||
Employees.staff_id.in_(staff_ids),
|
||||
).data
|
||||
|
||||
reachable_event_list_id = Event2Employee.get_event_id_by_employee_id(
|
||||
employee_id=employee.id
|
||||
)
|
||||
|
|
@ -167,12 +169,11 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
department = Departments.filter_one(
|
||||
Departments.id == duties.department_id,
|
||||
).data
|
||||
bulk_id = Duty.filter_one(
|
||||
Duty.duty_code == "BULK",
|
||||
).data
|
||||
bulk_duty_id = Duties.filter_one(
|
||||
Duties.company_id == selected_company.id,
|
||||
Duties.duties_id == bulk_id.id,
|
||||
bulk_id = Duty.filter_by_one(system=True, duty_code="BULK").data
|
||||
bulk_duty_id = Duties.filter_by_one(
|
||||
company_id=selected_company.id,
|
||||
duties_id=bulk_id.id,
|
||||
**Duties.valid_record_dict,
|
||||
).data
|
||||
update_selected_to_redis(
|
||||
request=request,
|
||||
|
|
@ -189,7 +190,6 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
employee_id=employee.id,
|
||||
employee_uu_id=employee.uu_id.__str__(),
|
||||
reachable_event_list_id=reachable_event_list_id,
|
||||
# reachable_event_list_uu_id=reachable_event_list_uu_id,
|
||||
),
|
||||
)
|
||||
return JSONResponse(
|
||||
|
|
@ -200,23 +200,25 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
status_code=status.HTTP_200_OK,
|
||||
)
|
||||
elif isinstance(token_dict, OccupantTokenObject):
|
||||
occupant_type = OccupantTypes.filter_one(
|
||||
OccupantTypes.uu_id == data.occupant_uu_id
|
||||
occupant_type = OccupantTypes.filter_by_one(
|
||||
system=True, uu_id=data.occupant_uu_id
|
||||
).data
|
||||
if not occupant_type:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Occupant Type is not found",
|
||||
)
|
||||
build_part = BuildParts.filter_one(
|
||||
BuildParts.uu_id == data.build_part_uu_id,
|
||||
build_part = BuildParts.filter_by_one(
|
||||
system=True, uu_id=data.build_part_uu_id
|
||||
).data
|
||||
if not build_part:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Build Part is not found",
|
||||
)
|
||||
build = Build.filter_one(Build.id == build_part.build_id).data
|
||||
build = Build.filter_one(
|
||||
Build.id == build_part.build_id,
|
||||
).data
|
||||
related_company = RelationshipEmployee2Build.filter_one(
|
||||
RelationshipEmployee2Build.member_id == build.id,
|
||||
).data
|
||||
|
|
@ -233,8 +235,7 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
).data:
|
||||
reachable_event_list_id = (
|
||||
Event2Occupant.get_event_id_by_build_living_space_id(
|
||||
Event2Occupant.build_living_space_id
|
||||
== selected_occupant_type.id
|
||||
build_living_space_id=selected_occupant_type.id
|
||||
)
|
||||
)
|
||||
update_selected_to_redis(
|
||||
|
|
@ -254,7 +255,6 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
responsible_company_id=company_related.id,
|
||||
responsible_company_uuid=company_related.uu_id.__str__(),
|
||||
reachable_event_list_id=reachable_event_list_id,
|
||||
# reachable_event_list_uu_id=reachable_event_list_uu_id,
|
||||
),
|
||||
)
|
||||
return JSONResponse(
|
||||
|
|
@ -270,6 +270,7 @@ class AuthenticationSelectEventMethods(MethodToEvent):
|
|||
)
|
||||
|
||||
|
||||
|
||||
class AuthenticationCheckTokenEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "LOGIN"
|
||||
|
|
@ -284,10 +285,9 @@ class AuthenticationCheckTokenEventMethods(MethodToEvent):
|
|||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_login_with_domain_and_creds(
|
||||
cls,
|
||||
request,
|
||||
token_dict: typing.Union[EmployeeSelection, OccupantSelection],
|
||||
def authentication_check_token_is_valid(
|
||||
cls,
|
||||
request,
|
||||
):
|
||||
if get_object_via_access_key(request=request):
|
||||
return JSONResponse(
|
||||
|
|
@ -652,6 +652,52 @@ class AuthenticationForgotPasswordEventMethods(MethodToEvent):
|
|||
)
|
||||
|
||||
|
||||
class AuthenticationResetPasswordEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "UPDATE"
|
||||
__event_keys__ = {
|
||||
"af9e121e-24bb-44ac-a616-471d5754360e": "authentication_reset_password",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_reset_password(cls, data: Forgot):
|
||||
from sqlalchemy import or_
|
||||
|
||||
found_user = Users.query.filter(
|
||||
or_(
|
||||
Users.email == str(data.access_key).lower(),
|
||||
Users.phone_number == str(data.access_key).replace(" ", ""),
|
||||
),
|
||||
).first()
|
||||
if not found_user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Given access key or domain is not matching with the any user record.",
|
||||
)
|
||||
|
||||
reset_password_token = found_user.reset_password_token(found_user=found_user)
|
||||
send_email_completed = send_email(
|
||||
subject=f"Dear {found_user.user_tag}, a password reset request has been received.",
|
||||
receivers=[str(found_user.email)],
|
||||
html=change_your_password_template(
|
||||
user_name=found_user.user_tag,
|
||||
forgot_link=ApiStatic.forgot_link(forgot_key=reset_password_token),
|
||||
),
|
||||
)
|
||||
if not send_email_completed:
|
||||
raise found_user.raise_http_exception(
|
||||
status_code=400, message="Email can not be sent. Try again later"
|
||||
)
|
||||
return JSONResponse(
|
||||
content={
|
||||
"completed": True,
|
||||
"message": "Password change link is sent to your email or phone",
|
||||
"data": found_user.get_dict(),
|
||||
},
|
||||
status_code=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
class AuthenticationDownloadAvatarEventMethods(MethodToEvent):
|
||||
|
||||
event_type = "LOGIN"
|
||||
|
|
@ -666,27 +712,28 @@ class AuthenticationDownloadAvatarEventMethods(MethodToEvent):
|
|||
}
|
||||
|
||||
@classmethod
|
||||
def authentication_download_avatar(cls, data: Forgot):
|
||||
if found_user := Users.check_user_exits(
|
||||
access_key=data.access_key, domain=data.domain
|
||||
):
|
||||
def authentication_download_avatar(cls, token_dict: Union[
|
||||
EmployeeTokenObject, OccupantTokenObject
|
||||
]):
|
||||
if found_user := Users.filter_one(Users.id == token_dict.user_id).data:
|
||||
expired_starts = str(
|
||||
system_arrow.now() - system_arrow.get(str(found_user.expiry_ends))
|
||||
)
|
||||
expired_int = int(
|
||||
system_arrow.now() - system_arrow.get(str(found_user.expiry_ends)).days
|
||||
)
|
||||
expired_int = (
|
||||
system_arrow.now() - system_arrow.get(str(found_user.expiry_ends))
|
||||
).days
|
||||
|
||||
return JSONResponse(
|
||||
content={
|
||||
"completed": True,
|
||||
"message": "Avatar and profile is shared via user credentials",
|
||||
"data": {
|
||||
"last_seen": str(found_user.last_seen),
|
||||
"full_name": found_user.person.full_name,
|
||||
"avatar": found_user.avatar,
|
||||
"remember_me": found_user.remember_me,
|
||||
"expiry_ends": str(found_user.expiry_ends),
|
||||
"expired_str": expired_starts,
|
||||
"expired_int": expired_int,
|
||||
"expired_int": int(expired_int),
|
||||
},
|
||||
},
|
||||
status_code=status.HTTP_200_OK,
|
||||
|
|
@ -730,6 +777,9 @@ AuthenticationForgotPasswordEventMethod = AuthenticationForgotPasswordEventMetho
|
|||
AuthenticationDownloadAvatarEventMethod = AuthenticationDownloadAvatarEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/avatar")
|
||||
)
|
||||
AuthenticationResetPasswordEventMethod = AuthenticationResetPasswordEventMethods(
|
||||
action=ActionsSchema(endpoint="/authentication/reset_password")
|
||||
)
|
||||
|
||||
# UserLogger.log_error(
|
||||
# str(
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class DecisionBookPersonListEventMethods(MethodToEvent):
|
|||
|
||||
@classmethod
|
||||
def building_decision_book_person_list(
|
||||
cls, data: ListOptions, token_dict: EmployeeTokenObject
|
||||
cls, data: ListOptions, token_dict: typing.Union[EmployeeTokenObject, OccupantTokenObject],
|
||||
):
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ class ServiceBindOccupantEventMethods(MethodToEvent):
|
|||
occupants_build_part = BuildParts.filter_one(
|
||||
BuildParts.uu_id == data.build_part_uu_id,
|
||||
BuildParts.build_id == token_dict.selected_occupant.build_id,
|
||||
BuildParts.active == True,
|
||||
).data
|
||||
if not occupants_build_part:
|
||||
return JSONResponse(
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class EventsListEventMethods(MethodToEvent):
|
|||
)
|
||||
return AlchemyJsonResponse(
|
||||
completed=True,
|
||||
message="DecisionBook are listed successfully",
|
||||
message="Events are listed successfully",
|
||||
result=records,
|
||||
)
|
||||
elif isinstance(token_dict, EmployeeTokenObject):
|
||||
|
|
@ -62,12 +62,12 @@ class EventsListEventMethods(MethodToEvent):
|
|||
)
|
||||
return AlchemyJsonResponse(
|
||||
completed=True,
|
||||
message="DecisionBook are listed successfully",
|
||||
message="Events are listed successfully",
|
||||
result=records,
|
||||
)
|
||||
return AlchemyJsonResponse(
|
||||
completed=False,
|
||||
message="DecisionBook are NOT listed successfully",
|
||||
message="Events are NOT listed successfully",
|
||||
result=[],
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ def parse_token_object_to_dict(request): # from requests import Request
|
|||
or str(endpoint_name) in Config.NOT_SECURE_PATHS
|
||||
):
|
||||
return valid_token
|
||||
if 'update' in endpoint_name:
|
||||
endpoint_name = endpoint_name.split('update')[0] + "update"
|
||||
if "update" in endpoint_name:
|
||||
endpoint_name = endpoint_name.split("update")[0] + "update"
|
||||
endpoint_active = EndpointRestriction.filter_one(
|
||||
EndpointRestriction.endpoint_name.ilike(f"%{endpoint_name}%"),
|
||||
system=True,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from typing import Optional
|
||||
from datetime import datetime
|
||||
from api_validations.core_validations import BaseModelRegular
|
||||
from api_validations.validations_request import (
|
||||
PydanticBaseModel,
|
||||
|
|
@ -59,8 +60,8 @@ class InsertBuild(BaseModelRegular, BuildValidation):
|
|||
max_floor: int
|
||||
underground_floor: int
|
||||
address_uu_id: str
|
||||
build_date: str
|
||||
decision_period_date: str
|
||||
build_date: datetime
|
||||
decision_period_date: datetime
|
||||
|
||||
tax_no: Optional[str] = None
|
||||
lift_count: Optional[int] = None
|
||||
|
|
@ -90,7 +91,7 @@ class UpdateBuild(PydanticBaseModel, BuildUpdateValidation):
|
|||
build_types: Optional[str] = None
|
||||
max_floor: Optional[int] = None
|
||||
underground_floor: Optional[int] = None
|
||||
build_date: Optional[str] = None
|
||||
build_date: Optional[datetime] = None
|
||||
tax_no: Optional[str] = None
|
||||
lift_count: Optional[int] = None
|
||||
heating_system: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ class ListOptions(BaseModelRegular, ListOptionsValidation):
|
|||
size: Optional[int] = 10
|
||||
order_field: Optional[str] = "id"
|
||||
order_type: Optional[str] = "asc"
|
||||
include_joins: Optional[list] = []
|
||||
query: Optional[dict] = {}
|
||||
include_joins: Optional[list] = None
|
||||
query: Optional[dict] = None
|
||||
|
||||
|
||||
class CrudRecordValidation:
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class RegisterEvents2EmployeeValidation:
|
|||
|
||||
|
||||
class RegisterEvents2Employee(BaseModelRegular, RegisterEvents2EmployeeValidation):
|
||||
event_uu_id_list: list[str] = []
|
||||
event_uu_id_list: list[str] = None
|
||||
employee_uu_id: Optional[str] = None
|
||||
|
||||
|
||||
|
|
@ -36,6 +36,6 @@ class RegisterEvents2OccupantValidation:
|
|||
|
||||
|
||||
class RegisterEvents2Occupant(BaseModelRegular, RegisterEvents2OccupantValidation):
|
||||
event_uu_id_list: list[str] = []
|
||||
event_uu_id_list: list[str] = None
|
||||
build_part_uu_id: Optional[str] = None
|
||||
occupant_uu_id: Optional[str] = None
|
||||
|
|
|
|||
|
|
@ -196,7 +196,6 @@ class Build(CrudCollection, SelectActionWithEmployee):
|
|||
foreign_keys="BuildDecisionBook.build_id",
|
||||
)
|
||||
|
||||
#
|
||||
# build_ibans: Mapped["BuildIbans"] = relationship(
|
||||
# "BuildIbans", back_populates="building", foreign_keys="BuildIbans.build_id"
|
||||
# )
|
||||
|
|
@ -271,21 +270,20 @@ class Build(CrudCollection, SelectActionWithEmployee):
|
|||
@classmethod
|
||||
def update_action(cls, data: UpdateBuild, build_uu_id: str, token):
|
||||
from databases import Addresses
|
||||
print('data_dict', data.dump())
|
||||
|
||||
print("data_dict", data.dump())
|
||||
data_dict = data.excluded_dump()
|
||||
if data.address_uu_id:
|
||||
official_address = Addresses.filter_one(
|
||||
Addresses.uu_id == data.address_uu_id
|
||||
).data
|
||||
data_dict["address_id"] = official_address.id if official_address else None
|
||||
print('data_dict', data_dict)
|
||||
if build_to_update := cls.filter_one(
|
||||
cls.uu_id == build_uu_id
|
||||
).data:
|
||||
print('build_to_update', build_to_update.get_dict())
|
||||
print("data_dict", data_dict)
|
||||
if build_to_update := cls.filter_one(cls.uu_id == build_uu_id).data:
|
||||
print("build_to_update", build_to_update.get_dict())
|
||||
updated_build = build_to_update.update(**data_dict)
|
||||
updated_build.save()
|
||||
print('updated_build', updated_build.get_dict())
|
||||
print("updated_build", updated_build.get_dict())
|
||||
return updated_build
|
||||
|
||||
@property
|
||||
|
|
|
|||
|
|
@ -345,7 +345,9 @@ class People(CrudCollection, SelectAction):
|
|||
|
||||
@property
|
||||
def full_name(self):
|
||||
return f"{self.firstname} {self.middle_name} {self.surname}"
|
||||
if self.middle_name:
|
||||
return f"{self.firstname} {self.middle_name} {self.surname}"
|
||||
return f"{self.firstname} {self.surname}"
|
||||
|
||||
@classmethod
|
||||
def create_action(cls, data: InsertPerson, token):
|
||||
|
|
|
|||
|
|
@ -126,8 +126,8 @@ def authentication_forgot_password(request: Request, data: Forgot):
|
|||
|
||||
|
||||
@login_route.post(path="/avatar", summary="Get link of avatar with credentials")
|
||||
def authentication_download_avatar(request: Request, data: Forgot):
|
||||
def authentication_download_avatar(request: Request):
|
||||
token_dict = parse_token_object_to_dict(request=request)
|
||||
return AuthenticationDownloadAvatarEventMethod.authentication_download_avatar(
|
||||
data=data, request=request, token_dict=token_dict
|
||||
token_dict=token_dict
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,44 @@ class EndpointValidationResponse(BaseModel):
|
|||
validation: dict
|
||||
|
||||
|
||||
class ValidationParser:
|
||||
|
||||
def __init__(self, active_validation):
|
||||
self.annotations = (
|
||||
active_validation.__annotations__.items() if active_validation else None
|
||||
)
|
||||
self.schema = {}
|
||||
self.parse()
|
||||
|
||||
def parse(self):
|
||||
for key, value in self.annotations or {}:
|
||||
field_type, required = "string", False
|
||||
if str(value) == "<class 'str'>" or str(value) == "typing.Optional[str]":
|
||||
field_type = "string"
|
||||
required = not str(value) == "typing.Optional[str]"
|
||||
elif str(value) == "<class 'int'>" or str(value) == "typing.Optional[int]":
|
||||
field_type = "integer"
|
||||
required = not str(value) == "typing.Optional[int]"
|
||||
elif (
|
||||
str(value) == "<class 'bool'>" or str(value) == "typing.Optional[bool]"
|
||||
):
|
||||
field_type = "boolean"
|
||||
required = not str(value) == "typing.Optional[bool]"
|
||||
elif (
|
||||
str(value) == "<class 'float'>"
|
||||
or str(value) == "typing.Optional[float]"
|
||||
):
|
||||
field_type = "float"
|
||||
required = not str(value) == "typing.Optional[bool]"
|
||||
elif (
|
||||
str(value) == "<class 'datetime.datetime'>"
|
||||
or str(value) == "typing.Optional[datetime.datetime]"
|
||||
):
|
||||
field_type = "datetime"
|
||||
required = not str(value) == "typing.Optional[datetime.datetime]"
|
||||
self.schema[key] = {"type": field_type, "required": required}
|
||||
|
||||
|
||||
def retrieve_validation_from_class(selected_event, events):
|
||||
event_function_class = getattr(selected_event, "function_class", None)
|
||||
event_function_code = getattr(selected_event, "function_code", None)
|
||||
|
|
@ -77,9 +115,9 @@ def user_list(request: Request, validation: EndpointValidation):
|
|||
headers = getattr(
|
||||
active_validation, str(valid_token.lang).lower(), active_validation.tr
|
||||
)
|
||||
print("headers", headers)
|
||||
validation_parse = ValidationParser(active_validation=active_validation)
|
||||
return EndpointValidationResponse(
|
||||
language=valid_token.lang,
|
||||
headers=headers,
|
||||
validation=active_validation.model_json_schema(),
|
||||
validation=validation_parse.schema,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -78,8 +78,15 @@ def is_bank_retrieve_account_records(bank_data):
|
|||
data_dict["bank_date_d"] = bank_date.day
|
||||
data_dict["bank_date_y"] = bank_date.year
|
||||
data_dict["bank_date"] = str(bank_date)
|
||||
if build_iban := BuildIbans.filter_by_one(iban=data_dict["iban"], system=True).data:
|
||||
data_dict.update({"build_id": build_iban.build_id, "build_uu_id": build_iban.build_uu_id})
|
||||
if build_iban := BuildIbans.filter_by_one(
|
||||
iban=data_dict["iban"], system=True
|
||||
).data:
|
||||
data_dict.update(
|
||||
{
|
||||
"build_id": build_iban.build_id,
|
||||
"build_uu_id": build_iban.build_uu_id,
|
||||
}
|
||||
)
|
||||
if found_record := AccountRecords.filter_one(
|
||||
AccountRecords.bank_date == data_dict["bank_date"],
|
||||
AccountRecords.iban == data_dict["iban"],
|
||||
|
|
|
|||
Loading…
Reference in New Issue