from __future__ import annotations
from base64 import b64encode
from dataclasses import dataclass
from enum import Enum
from typing import Optional
from pathlib import Path
from q2_sdk.core.exceptions import BadParameterError
from datetime import datetime
from decimal import Decimal
HERE = Path(__file__).absolute().parent
[docs]
class DepositItemRequestType(Enum):
DepositItemList = 30 # TranItemDetailList
DepositItemImage = 31 # TranItemDetailImage
[docs]
@dataclass
class DepositItemRequest:
internal_account_number: str
transaction_id: int
transaction_type: DepositItemRequestType
host_account_id: Optional[int] = None
external_account_number: Optional[str] = None
cif_internal: Optional[str] = None
cif_external: Optional[str] = None
item_list_requests: Optional[list[DepositItemListRequest]] = None
item_image_requests: Optional[list[DepositItemImageRequest]] = None
user_data: Optional[str] = None
[docs]
@staticmethod
def from_hq_request(inp: dict) -> DepositItemRequest:
host_account = inp["HostAccount_Req"][0]
internal_account_number = host_account["AccountNumberInternal"]
external_account_number = host_account["AccountNumberExternal"]
cif_internal = host_account["CifInternal"]
cif_external = host_account["CifExternal"]
transaction_type = host_account["TransactionType"]
transaction_id = host_account["TransactionID"]
host_account_id = host_account["HostAccountID"]
item_list_requests: list[DepositItemListRequest] = None
item_image_requests: list[DepositItemImageRequest] = None
if inp["TranItemDetailList_Req"]:
item_list_requests = [
DepositItemListRequest.from_hq_request(item_list_req)
for item_list_req in inp["TranItemDetailList_Req"]
]
elif inp["TranItemDetailImage_Req"]:
item_image_requests = [
DepositItemImageRequest.from_hq_request(image_req)
for image_req in inp["TranItemDetailImage_Req"]
]
user_data = inp["RequestorData"][0]["UserData"]
if not internal_account_number:
raise BadParameterError("AccountNumberInternal must be provided")
elif not transaction_id:
raise BadParameterError("TransactionID must be provided")
elif not item_image_requests and not item_list_requests:
raise BadParameterError(
"One of TranItemDetailList_Req or TranItemDetailImage_Req must be provided"
)
return DepositItemRequest(
internal_account_number,
transaction_id,
DepositItemRequestType(transaction_type),
host_account_id,
external_account_number,
cif_internal,
cif_external,
item_list_requests,
item_image_requests,
user_data,
)
[docs]
@dataclass
class DepositItemListRequest:
item_transaction_id: Optional[int] = None
transaction_date: Optional[datetime] = None
effective_date: Optional[datetime] = None
item_amount: Optional[Decimal] = None
host_tran_code: Optional[str] = None
item_description: Optional[str] = None
d_or_c: Optional[str] = None
image_number: Optional[str] = None
host_ref_number: Optional[str] = None
check_number: Optional[str] = None
host_transaction_id: Optional[int] = None
[docs]
def from_hq_request(inp: dict) -> DepositItemListRequest:
item_transaction_id = inp["TransactionID"]
transaction_date = inp["TransactionDate"]
effective_date = inp["EffectiveDate"]
item_amount = inp["TxnAmount"]
host_tran_code = inp["HostTranCode"]
item_description = inp["TxnDescription"]
d_or_c = inp["DorC"]
image_number = inp["ImageNumber"]
host_ref_number = inp["HostRefNumber"]
check_number = inp["CheckNumber"]
host_transaction_id = inp["HostTransactionID"]
return DepositItemListRequest(
item_transaction_id,
transaction_date,
effective_date,
item_amount,
host_tran_code,
item_description,
d_or_c,
image_number,
host_ref_number,
check_number,
host_transaction_id,
)
[docs]
@dataclass
class DepositItem:
image_available: bool
description: Optional[str] = None
aba: Optional[str] = None
transaction_date: Optional[datetime] = None
account_number: Optional[str] = None
amount: Optional[Decimal] = None
check_number: Optional[str] = None
[docs]
def as_adapter_response(self) -> dict[str, str]:
return {
"ImageAvailable": self.image_available,
"TxnDescription": self.description,
"ABA": self.aba,
"TransactionDate": self.transaction_date,
"AccountNumber": self.account_number,
"TxnAmount": self.amount,
"CheckNumber": self.check_number,
}
[docs]
@dataclass
class DepositItemImageRequest:
item_transaction_id: Optional[int] = None
transaction_date: Optional[datetime] = None
item_amount: Optional[Decimal] = None
host_tran_code: Optional[str] = None
item_description: Optional[str] = None
d_or_c: Optional[str] = None
image_number: Optional[str] = None
host_ref_number: Optional[str] = None
check_number: Optional[str] = None
aba: Optional[str] = None
account_number: Optional[str] = None
account_type: Optional[str] = None
[docs]
def from_hq_request(inp: dict) -> DepositItemImageRequest:
item_transaction_id = inp["TransactionID"]
transaction_date = inp["TransactionDate"]
item_amount = inp["TxnAmount"]
host_tran_code = inp["HostTranCode"]
item_description = inp["TxnDescription"]
d_or_c = inp["DorC"]
image_number = inp["ImageNumber"]
host_ref_number = inp["HostRefNumber"]
check_number = inp["CheckNumber"]
aba = inp["ABA"]
account_number = inp["AccountNumber"]
account_type = inp["AccountType"]
return DepositItemImageRequest(
item_transaction_id,
transaction_date,
item_amount,
host_tran_code,
item_description,
d_or_c,
image_number,
host_ref_number,
check_number,
aba,
account_number,
account_type,
)
[docs]
@dataclass
class DepositItemImage:
raw: bytes
image_type: ImageType
[docs]
def as_base64(self) -> str:
return b64encode(self.raw).decode()
[docs]
def as_adapter_response(self, transaction_id) -> dict[str, str]:
return {
"ImageData": self.as_base64(),
"ImageType": self.image_type.value,
"TransactionID": transaction_id,
}
[docs]
class MockImage:
[docs]
@staticmethod
def get_front() -> bytes:
return Path.read_bytes(HERE / "check_front.png")
[docs]
@staticmethod
def get_back() -> bytes:
return Path.read_bytes(HERE / "check_back.png")
[docs]
class ImageType(Enum):
GIF = 0
JPG = 1
BMP = 2
PNG = 3
PDF = 4
TIFF = 5