Skip to content

Commit 96ba747

Browse files
Bank checks (beta) (#94)
* new: ✨ New Field type Position for position onfly features * chg: ✨ added Bank_check (beta) to endpoint and client definitions * chg: ✨ Added BankCheck class * new: ✨ Added Position field type and BankCheck class * new: ✅ Added tests for Position field and BankCheck class * fix: 🐛 Fixed non used import * minor fixes to types and for lint Co-authored-by: Ianaré Sévi <ianare@mindee.co>
1 parent c29f421 commit 96ba747

File tree

11 files changed

+1272
-0
lines changed

11 files changed

+1272
-0
lines changed

docs/documents.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ Financial Document
3333
:inherited-members:
3434
:undoc-members:
3535

36+
Bank Check
37+
----------
38+
.. autoclass:: mindee.documents.bank_check.BankCheck
39+
:members:
40+
:inherited-members:
41+
:undoc-members:
42+
3643
Custom Document
3744
----------------
3845
.. autoclass:: mindee.documents.custom_document.CustomDocument

mindee/client.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
from typing import BinaryIO, Dict, Optional
33

44
from mindee.document_config import DocumentConfig, DocumentConfigDict
5+
from mindee.documents.bank_check import BankCheck
56
from mindee.documents.custom_document import CustomDocument
67
from mindee.documents.financial_document import FinancialDocument
78
from mindee.documents.invoice import Invoice
89
from mindee.documents.passport import Passport
910
from mindee.documents.receipt import Receipt
1011
from mindee.endpoints import (
1112
OTS_OWNER,
13+
BankCheckEndpoint,
1214
CustomEndpoint,
1315
HTTPException,
1416
InvoiceEndpoint,
@@ -247,6 +249,22 @@ def config_passport(self, api_key: Optional[str] = None) -> "Client":
247249
self._doc_configs[(OTS_OWNER, "passport")] = config
248250
return self
249251

252+
def config_bank_check(self, api_key: Optional[str] = None) -> "Client":
253+
"""
254+
Configure a Mindee Bank check document.
255+
256+
:param api_key: Bank check API key
257+
"""
258+
config = DocumentConfig(
259+
document_type="bank_check",
260+
singular_name="bank_check",
261+
plural_name="bank_checks",
262+
constructor=BankCheck,
263+
endpoints=[BankCheckEndpoint(api_key=api_key)],
264+
)
265+
self._doc_configs[(OTS_OWNER, "bank_check")] = config
266+
return self
267+
250268
def doc_from_path(
251269
self,
252270
input_path: str,

mindee/documents/bank_check.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
from typing import List, Optional
2+
3+
from mindee.documents.base import Document, TypeApiPrediction
4+
from mindee.fields.amount import Amount
5+
from mindee.fields.base import Field
6+
from mindee.fields.date import Date
7+
from mindee.fields.orientation import Orientation
8+
from mindee.fields.position import Position
9+
10+
11+
class BankCheck(Document):
12+
date: Date
13+
"""Date the check was issued"""
14+
amount: Amount
15+
"""Total including taxes"""
16+
payees: List[Field] = []
17+
"""List of payees (full name or company name)"""
18+
check_number: Field
19+
"""Check number"""
20+
routing_number: Field
21+
"""Payer's bank account routing number"""
22+
account_number: Field
23+
"""Payer's bank account number"""
24+
check_position: Field
25+
"""Check's position in the image"""
26+
signatures_positions: List[Field] = []
27+
"""Signatures' positions in the image"""
28+
# orientation is only present on page-level, not document-level
29+
orientation: Optional[Orientation] = None
30+
"""Page orientation"""
31+
32+
def __init__(
33+
self,
34+
api_prediction=None,
35+
input_file=None,
36+
page_n: Optional[int] = None,
37+
document_type="bank_check",
38+
):
39+
"""
40+
Bank check document.
41+
42+
:param api_prediction: Raw prediction from HTTP response
43+
:param input_file: Input object
44+
:param page_n: Page number for multi pages pdf input
45+
"""
46+
super().__init__(
47+
input_file=input_file,
48+
document_type=document_type,
49+
api_prediction=api_prediction,
50+
page_n=page_n,
51+
)
52+
53+
def _build_from_api_prediction(
54+
self, api_prediction: TypeApiPrediction, page_n: Optional[int] = None
55+
) -> None:
56+
"""
57+
Build the document from an API response JSON.
58+
59+
:param api_prediction: Raw prediction from HTTP response
60+
:param page_n: Page number for multi pages pdf input
61+
"""
62+
if page_n is not None:
63+
self.orientation = Orientation(api_prediction["orientation"], page_n=page_n)
64+
65+
self.routing_number = Field(api_prediction["routing_number"], page_n=page_n)
66+
self.account_number = Field(api_prediction["account_number"], page_n=page_n)
67+
self.check_number = Field(api_prediction["check_number"], page_n=page_n)
68+
self.date = Date(api_prediction["date"], "value", page_n=page_n)
69+
self.amount = Amount(api_prediction["amount"], value_key="value", page_n=page_n)
70+
self.payees = [
71+
Field(payee, page_n=page_n) for payee in api_prediction["payees"]
72+
]
73+
self.check_position = Position(api_prediction["check_position"], page_n=page_n)
74+
self.signatures_positions = [
75+
Position(signature_position, page_n=page_n)
76+
for signature_position in api_prediction["signatures_positions"]
77+
]
78+
79+
def __str__(self) -> str:
80+
payees = ", ".join(
81+
[payee.value if payee.value is not None else "" for payee in self.payees]
82+
)
83+
return (
84+
"-----Bank check data-----\n"
85+
f"Filename: {self.filename}\n"
86+
f"Routing number: {self.routing_number}\n"
87+
f"Account number: {self.account_number}\n"
88+
f"Check number: {self.check_number}\n"
89+
f"Date: {self.date}\n"
90+
f"Amount: {self.amount}\n"
91+
f"Payees: {payees}\n"
92+
"----------------------"
93+
)
94+
95+
def _checklist(self) -> None:
96+
"""Call check methods."""
97+
self.checklist = {}

mindee/endpoints.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
PASSPORT_VERSION = "1"
2323
PASSPORT_URL_NAME = "passport"
2424

25+
BANK_CHECK_VERSION = "1"
26+
BANK_CHECK_URL_NAME = "bank_check"
27+
2528

2629
class Endpoint:
2730
"""Generic API endpoint for a product."""
@@ -189,5 +192,15 @@ def __init__(self, api_key: Optional[str] = None):
189192
)
190193

191194

195+
class BankCheckEndpoint(Endpoint):
196+
def __init__(self, api_key: Optional[str] = None):
197+
super().__init__(
198+
owner=OTS_OWNER,
199+
url_name=BANK_CHECK_URL_NAME,
200+
version=BANK_CHECK_VERSION,
201+
api_key=api_key,
202+
)
203+
204+
192205
class HTTPException(RuntimeError):
193206
"""An exception relating to HTTP calls."""

mindee/fields/position.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from typing import Optional
2+
3+
from mindee.fields.base import Field, TypePrediction
4+
from mindee.geometry import Polygon, Quadrilateral
5+
6+
7+
class Position(Field):
8+
value: Polygon = []
9+
quadrangle: Optional[Quadrilateral]
10+
rectangle: Optional[Quadrilateral]
11+
bounding_box: Optional[Quadrilateral]
12+
13+
def __init__(
14+
self,
15+
position_prediction: TypePrediction,
16+
value_key: str = "polygon",
17+
reconstructed: bool = False,
18+
page_n: Optional[int] = None,
19+
):
20+
"""
21+
Amount field object.
22+
23+
:param position_prediction: Position prediction object from HTTP response
24+
:param value_key: Key to use in the position_prediction dict
25+
:param reconstructed: Bool for reconstructed object (not extracted in the API)
26+
:param page_n: Page number for multi-page PDF
27+
"""
28+
super().__init__(
29+
position_prediction,
30+
value_key=value_key,
31+
reconstructed=reconstructed,
32+
page_n=page_n,
33+
)
34+
try:
35+
self.value = position_prediction[value_key]
36+
self.bounding_box = (
37+
position_prediction["bounding_box"]
38+
if "bounding_box" in position_prediction.keys()
39+
else None
40+
)
41+
self.quadrangle = (
42+
position_prediction["quadrangle"]
43+
if "quadrangle" in position_prediction.keys()
44+
else None
45+
)
46+
self.polygon = (
47+
position_prediction["polygon"]
48+
if "polygon" in position_prediction.keys()
49+
else None
50+
)
51+
self.rectangle = (
52+
position_prediction["rectangle"]
53+
if "rectangle" in position_prediction.keys()
54+
else None
55+
)
56+
except (ValueError, TypeError, KeyError):
57+
self.value = []
58+
self.confidence = 0.0

tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
RECEIPT_DATA_DIR = "./tests/data/receipt"
22
INVOICE_DATA_DIR = "./tests/data/invoice"
33
PASSPORT_DATA_DIR = "./tests/data/passport"
4+
BANK_CHECK_DATA_DIR = "./tests/data/bank_check"
45
CUSTOM_DATA_DIR = "./tests/data/custom"

0 commit comments

Comments
 (0)