Skip to content

Commit 30bebd9

Browse files
authored
✨ add support for: proof of address v1 (#120)
1 parent 4b80f1a commit 30bebd9

File tree

7 files changed

+202
-6
lines changed

7 files changed

+202
-6
lines changed

mindee/cli.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ class CommandConfig(Generic[TypeDoc]):
3838
help="Financial Document (receipt or invoice)",
3939
doc_class=documents.TypeFinancialV1,
4040
),
41+
"proof-of-address": CommandConfig(
42+
help="Proof of Address",
43+
doc_class=documents.TypeProofOfAddressV1,
44+
),
4145
"us-check": CommandConfig(
4246
help="US Bank Check",
4347
doc_class=documents.us.TypeBankCheckV1,

mindee/client.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@
99
InvoiceV3,
1010
InvoiceV4,
1111
PassportV1,
12+
ProofOfAddressV1,
1213
ReceiptV3,
1314
ReceiptV4,
15+
fr,
16+
us,
1417
)
1518
from mindee.documents.base import Document, TypeDocument
1619
from mindee.documents.config import DocumentConfig, DocumentConfigDict
17-
from mindee.documents.fr import CarteGriseV1
18-
from mindee.documents.us import BankCheckV1
1920
from mindee.endpoints import OTS_OWNER, CustomEndpoint, HTTPException, StandardEndpoint
2021
from mindee.input.page_options import PageOptions
2122
from mindee.input.sources import (
@@ -259,24 +260,33 @@ def _init_default_endpoints(self) -> None:
259260
)
260261
],
261262
),
262-
(OTS_OWNER, BankCheckV1.__name__): DocumentConfig(
263+
(OTS_OWNER, us.BankCheckV1.__name__): DocumentConfig(
263264
document_type="bank_check_v1",
264-
document_class=BankCheckV1,
265+
document_class=us.BankCheckV1,
265266
endpoints=[
266267
StandardEndpoint(
267268
url_name="bank_check", version="1", api_key=self.api_key
268269
)
269270
],
270271
),
271-
(OTS_OWNER, CarteGriseV1.__name__): DocumentConfig(
272+
(OTS_OWNER, fr.CarteGriseV1.__name__): DocumentConfig(
272273
document_type="carte_grise_v1",
273-
document_class=CarteGriseV1,
274+
document_class=fr.CarteGriseV1,
274275
endpoints=[
275276
StandardEndpoint(
276277
url_name="carte_grise", version="1", api_key=self.api_key
277278
)
278279
],
279280
),
281+
(OTS_OWNER, ProofOfAddressV1.__name__): DocumentConfig(
282+
document_type="proof_of_address_v1",
283+
document_class=ProofOfAddressV1,
284+
endpoints=[
285+
StandardEndpoint(
286+
url_name="proof_of_address", version="1", api_key=self.api_key
287+
)
288+
],
289+
),
280290
(OTS_OWNER, CropperV1.__name__): DocumentConfig(
281291
document_type="cropper_v1",
282292
document_class=CropperV1,

mindee/documents/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@
99
)
1010
from mindee.documents.invoice import InvoiceV3, InvoiceV4, TypeInvoiceV3, TypeInvoiceV4
1111
from mindee.documents.passport import PassportV1, TypePassportV1
12+
from mindee.documents.proof_of_address import ProofOfAddressV1, TypeProofOfAddressV1
1213
from mindee.documents.receipt import ReceiptV3, ReceiptV4, TypeReceiptV3, TypeReceiptV4
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .proof_of_address_v1 import ProofOfAddressV1, TypeProofOfAddressV1
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
from typing import List, Optional, TypeVar
2+
3+
from mindee.documents.base import Document, TypeApiPrediction, clean_out_string
4+
from mindee.fields.company_registration import CompanyRegistrationField
5+
from mindee.fields.date import DateField
6+
from mindee.fields.locale import LocaleField
7+
from mindee.fields.text import TextField
8+
9+
10+
class ProofOfAddressV1(Document):
11+
locale: LocaleField
12+
"""locale information"""
13+
date: DateField
14+
"""ISO date yyyy-mm-dd. Works both for European and US dates."""
15+
dates: List[DateField] = []
16+
"""All extracted ISO date yyyy-mm-dd"""
17+
issuer_address: TextField
18+
"""Address of the document's issuer."""
19+
issuer_company_registration: List[CompanyRegistrationField] = []
20+
"""Generic: VAT NUMBER, TAX ID, COMPANY REGISTRATION NUMBER or country specific."""
21+
issuer_name: TextField
22+
"""Name of the person or company issuing the document."""
23+
recipient_address: TextField
24+
"""Address of the recipient."""
25+
recipient_company_registration: List[CompanyRegistrationField] = []
26+
"""Generic: VAT NUMBER, TAX ID, COMPANY REGISTRATION NUMBER or country specific."""
27+
recipient_name: TextField
28+
"""Name of the document's recipient."""
29+
30+
def __init__(
31+
self,
32+
api_prediction=None,
33+
input_source=None,
34+
page_n: Optional[int] = None,
35+
document_type="proof_of_address",
36+
):
37+
"""
38+
Proof of Address document.
39+
40+
:param api_prediction: Raw prediction from HTTP response
41+
:param input_source: Input object
42+
:param page_n: Page number for multi pages pdf input
43+
"""
44+
super().__init__(
45+
input_source=input_source,
46+
document_type=document_type,
47+
api_prediction=api_prediction,
48+
page_n=page_n,
49+
)
50+
self._build_from_api_prediction(api_prediction["prediction"], page_n=page_n)
51+
52+
def _build_from_api_prediction(
53+
self, api_prediction: TypeApiPrediction, page_n: Optional[int] = None
54+
) -> None:
55+
"""
56+
Build the object from the prediction API JSON.
57+
58+
:param api_prediction: Raw prediction from HTTP response
59+
:param page_n: Page number for multi pages pdf input
60+
"""
61+
self.locale = LocaleField(
62+
api_prediction["locale"], value_key="language", page_n=page_n
63+
)
64+
self.date = DateField(api_prediction["date"], page_n=page_n)
65+
self.dates = [
66+
DateField(tax_prediction, page_n=page_n)
67+
for tax_prediction in api_prediction["dates"]
68+
]
69+
self.issuer_name = TextField(api_prediction["issuer_name"], page_n=page_n)
70+
self.issuer_address = TextField(api_prediction["issuer_address"], page_n=page_n)
71+
self.issuer_company_registration = [
72+
CompanyRegistrationField(tax_prediction, page_n=page_n)
73+
for tax_prediction in api_prediction["issuer_company_registration"]
74+
]
75+
self.recipient_name = TextField(api_prediction["recipient_name"], page_n=page_n)
76+
self.recipient_address = TextField(
77+
api_prediction["recipient_address"], page_n=page_n
78+
)
79+
self.recipient_company_registration = [
80+
CompanyRegistrationField(tax_prediction, page_n=page_n)
81+
for tax_prediction in api_prediction["recipient_company_registration"]
82+
]
83+
84+
def __str__(self) -> str:
85+
issuer_company_registrations = "; ".join(
86+
[str(n.value) for n in self.issuer_company_registration]
87+
)
88+
recipient_company_registrations = "; ".join(
89+
[str(n.value) for n in self.recipient_company_registration]
90+
)
91+
dates = "\n ".join([str(n.value) for n in self.dates])
92+
return clean_out_string(
93+
"----- Proof of Address V1 -----\n"
94+
f"Filename: {self.filename or ''}\n"
95+
f"Locale: {self.locale}\n"
96+
f"Issuer name: {self.issuer_name}\n"
97+
f"Issuer Address: {self.issuer_address}\n"
98+
f"Issuer Company Registrations: {issuer_company_registrations}\n"
99+
f"Recipient name: {self.recipient_name}\n"
100+
f"Recipient Address: {self.recipient_address}\n"
101+
f"Recipient Company Registrations: {recipient_company_registrations}\n"
102+
f"Issuance Date: {self.date}\n"
103+
f"Dates: {dates}\n"
104+
"----------------------"
105+
)
106+
107+
def _checklist(self) -> None:
108+
pass
109+
110+
111+
TypeProofOfAddressV1 = TypeVar("TypeProofOfAddressV1", bound=ProofOfAddressV1)

tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
INVOICE_DATA_DIR = "./tests/data/invoice"
33
FINANCIAL_DOC_DATA_DIR = "./tests/data/financial_document"
44
PASSPORT_DATA_DIR = "./tests/data/passport"
5+
PROOF_OF_ADDRESS_DATA_DIR = "./tests/data/proof_of_address"
56
US_BANK_CHECK_DATA_DIR = "./tests/data/us/bank_check"
67
FR_CARTE_GRISE_DATA_DIR = "./tests/data/fr/carte_grise"
78
CUSTOM_DATA_DIR = "./tests/data/custom"
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import json
2+
3+
import pytest
4+
5+
from mindee.documents.proof_of_address.proof_of_address_v1 import ProofOfAddressV1
6+
from tests import PROOF_OF_ADDRESS_DATA_DIR
7+
8+
FILE_PATH_PROOF_OF_ADDRESS_V1_COMPLETE = (
9+
f"{PROOF_OF_ADDRESS_DATA_DIR}/response_v1/complete.json"
10+
)
11+
12+
13+
@pytest.fixture
14+
def proof_of_address_v1_doc_object() -> ProofOfAddressV1:
15+
json_data = json.load(open(FILE_PATH_PROOF_OF_ADDRESS_V1_COMPLETE))
16+
return ProofOfAddressV1(
17+
api_prediction=json_data["document"]["inference"], page_n=None
18+
)
19+
20+
21+
@pytest.fixture
22+
def proof_of_address_v1_doc_object_empty() -> ProofOfAddressV1:
23+
json_data = json.load(open(f"{PROOF_OF_ADDRESS_DATA_DIR}/response_v1/empty.json"))
24+
return ProofOfAddressV1(
25+
api_prediction=json_data["document"]["inference"], page_n=None
26+
)
27+
28+
29+
@pytest.fixture
30+
def proof_of_address_v1_page_object() -> ProofOfAddressV1:
31+
json_data = json.load(open(FILE_PATH_PROOF_OF_ADDRESS_V1_COMPLETE))
32+
return ProofOfAddressV1(
33+
api_prediction=json_data["document"]["inference"]["pages"][0], page_n=0
34+
)
35+
36+
37+
def test_doc_constructor(proof_of_address_v1_doc_object):
38+
doc_str = (
39+
open(f"{PROOF_OF_ADDRESS_DATA_DIR}/response_v1/doc_to_string.txt")
40+
.read()
41+
.strip()
42+
)
43+
assert proof_of_address_v1_doc_object.issuer_name.page_n == 0
44+
assert str(proof_of_address_v1_doc_object) == doc_str
45+
46+
47+
def test_page_constructor(proof_of_address_v1_page_object):
48+
doc_str = (
49+
open(f"{PROOF_OF_ADDRESS_DATA_DIR}/response_v1/page0_to_string.txt")
50+
.read()
51+
.strip()
52+
)
53+
assert proof_of_address_v1_page_object.orientation.value == 0
54+
assert proof_of_address_v1_page_object.issuer_name.page_n == 0
55+
assert str(proof_of_address_v1_page_object) == doc_str
56+
assert len(proof_of_address_v1_page_object.cropper) == 0
57+
58+
59+
def test_all_na(proof_of_address_v1_doc_object_empty):
60+
assert proof_of_address_v1_doc_object_empty.locale.value is None
61+
assert proof_of_address_v1_doc_object_empty.date.value is None
62+
assert len(proof_of_address_v1_doc_object_empty.dates) == 0
63+
assert proof_of_address_v1_doc_object_empty.issuer_address.value is None
64+
assert len(proof_of_address_v1_doc_object_empty.issuer_company_registration) == 0
65+
assert proof_of_address_v1_doc_object_empty.issuer_name.value is None
66+
assert proof_of_address_v1_doc_object_empty.recipient_address.value is None
67+
assert len(proof_of_address_v1_doc_object_empty.recipient_company_registration) == 0
68+
assert proof_of_address_v1_doc_object_empty.recipient_name.value is None

0 commit comments

Comments
 (0)