Skip to content

Commit d23cb9d

Browse files
committed
✨ add support for financial documents v1.1
1 parent 94d6dd1 commit d23cb9d

File tree

27 files changed

+513
-329
lines changed

27 files changed

+513
-329
lines changed

mindee/documents/eu/license_plate/license_plate_v1.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def _build_from_api_prediction(
4141
:param page_n: Page number
4242
"""
4343
self.license_plates = [
44-
TextField(prediction, page_n=page_n)
44+
TextField(prediction, page_id=page_n)
4545
for prediction in api_prediction["license_plates"]
4646
]
4747

Lines changed: 179 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from typing import List, Optional, TypeVar
22

33
from mindee.documents.base import Document, TypeApiPrediction, clean_out_string
4-
from mindee.documents.invoice.line_item_v4 import InvoiceLineItemV4
54
from mindee.fields.amount import AmountField
65
from mindee.fields.classification import ClassificationField
76
from mindee.fields.company_registration import CompanyRegistrationField
@@ -11,52 +10,58 @@
1110
from mindee.fields.tax import Taxes
1211
from mindee.fields.text import TextField
1312

13+
from .financial_document_v1_line_item import FinancialDocumentV1LineItem
14+
1415

1516
class FinancialDocumentV1(Document):
16-
locale: LocaleField
17-
"""locale information"""
18-
total_amount: AmountField
19-
"""Total including taxes"""
20-
total_net: AmountField
21-
"""Total excluding taxes"""
17+
"""Financial Document v1 prediction results."""
18+
19+
category: ClassificationField
20+
"""The purchase category among predefined classes."""
21+
customer_address: TextField
22+
"""The address of the customer."""
23+
customer_company_registrations: List[CompanyRegistrationField]
24+
"""List of company registrations associated to the customer."""
25+
customer_name: TextField
26+
"""The name of the customer."""
2227
date: DateField
23-
"""Date the invoice was issued"""
28+
"""The date the purchase was made."""
29+
document_type: ClassificationField
30+
"""One of: 'INVOICE', 'CREDIT NOTE', 'CREDIT CARD RECEIPT', 'EXPENSE RECEIPT'."""
31+
due_date: DateField
32+
"""The date on which the payment is due."""
2433
invoice_number: TextField
25-
"""Invoice number"""
34+
"""The invoice number or identifier."""
35+
line_items: List[FinancialDocumentV1LineItem]
36+
"""List of line item details."""
37+
locale: LocaleField
38+
"""The locale detected on the document."""
2639
reference_numbers: List[TextField]
27-
"""List of Reference numbers including PO number."""
28-
due_date: DateField
29-
"""Date the invoice is due"""
30-
taxes: Taxes
31-
"""List of all taxes"""
32-
total_tax: AmountField
33-
"""Sum total of all taxes"""
34-
supplier_name: TextField
35-
"""Supplier 's name"""
40+
"""List of Reference numbers, including PO number."""
41+
subcategory: ClassificationField
42+
"""The purchase subcategory among predefined classes for transport and food."""
3643
supplier_address: TextField
37-
"""Supplier's address"""
44+
"""The address of the supplier or merchant."""
3845
supplier_company_registrations: List[CompanyRegistrationField]
39-
"""Company numbers"""
40-
customer_name: TextField
41-
"""Customer's name"""
42-
customer_address: TextField
43-
"""Customer's address"""
44-
customer_company_registrations: List[CompanyRegistrationField]
45-
"""Customer company registration numbers"""
46+
"""List of company registrations associated to the supplier."""
47+
supplier_name: TextField
48+
"""The name of the supplier or merchant."""
4649
supplier_payment_details: List[PaymentDetails]
47-
"""Payment details"""
48-
line_items: List[InvoiceLineItemV4]
49-
"""Details of line items"""
50-
tip: AmountField
51-
"""Total amount of tip and gratuity."""
50+
"""List of payment details associated to the supplier."""
51+
supplier_phone_number: TextField
52+
"""The phone number of the supplier or merchant."""
53+
taxes: Taxes
54+
"""List of tax lines information."""
5255
time: TextField
53-
"""Time as seen on the receipt in HH:MM format."""
54-
document_type: ClassificationField
55-
"""A classification field, among predefined classes."""
56-
category: ClassificationField
57-
"""The invoice or receipt category among predefined classes."""
58-
subcategory: ClassificationField
59-
"""The invoice or receipt sub-category among predefined classes."""
56+
"""The time the purchase was made."""
57+
tip: AmountField
58+
"""The total amount of tip and gratuity"""
59+
total_amount: AmountField
60+
"""The total amount paid: includes taxes, tips, fees, and other charges."""
61+
total_net: AmountField
62+
"""The net amount paid: does not include taxes, fees, and discounts."""
63+
total_tax: AmountField
64+
"""The total amount of taxes."""
6065

6166
def __init__(
6267
self,
@@ -65,18 +70,15 @@ def __init__(
6570
page_n: Optional[int] = None,
6671
):
6772
"""
68-
Union of `Invoice` and `Receipt`.
73+
Financial Document v1 prediction results.
6974
7075
:param api_prediction: Raw prediction from HTTP response
7176
:param input_source: Input object
72-
:param page_n: Page number for multi-page PDF input
77+
:param page_n: Page number for multi pages pdf input
7378
"""
74-
# need this for building from prediction
75-
self.input_file = input_source
76-
7779
super().__init__(
7880
input_source=input_source,
79-
document_type="financial_doc",
81+
document_type="financial_document",
8082
api_prediction=api_prediction,
8183
page_n=page_n,
8284
)
@@ -86,115 +88,175 @@ def _build_from_api_prediction(
8688
self, api_prediction: TypeApiPrediction, page_n: Optional[int] = None
8789
) -> None:
8890
"""
89-
Build the document from an API response JSON.
91+
Build the object from the prediction API JSON.
9092
9193
:param api_prediction: Raw prediction from HTTP response
92-
:param page_n: Page number for multi pages pdf input
94+
:param page_n: Page number
9395
"""
94-
self.supplier_company_registrations = [
95-
CompanyRegistrationField(field_dict, page_n=page_n)
96-
for field_dict in api_prediction["supplier_company_registrations"]
96+
self.category = ClassificationField(
97+
api_prediction["category"],
98+
page_id=page_n,
99+
)
100+
self.customer_address = TextField(
101+
api_prediction["customer_address"],
102+
page_id=page_n,
103+
)
104+
self.customer_company_registrations = [
105+
CompanyRegistrationField(prediction, page_id=page_n)
106+
for prediction in api_prediction["customer_company_registrations"]
97107
]
98-
self.date = DateField(api_prediction["date"], page_n=page_n)
99-
self.due_date = DateField(api_prediction["due_date"], page_n=page_n)
100-
self.invoice_number = TextField(api_prediction["invoice_number"], page_n=page_n)
101-
self.reference_numbers = [
102-
TextField(reference_number, page_n=page_n)
103-
for reference_number in api_prediction["reference_numbers"]
108+
self.customer_name = TextField(
109+
api_prediction["customer_name"],
110+
page_id=page_n,
111+
)
112+
self.date = DateField(
113+
api_prediction["date"],
114+
page_id=page_n,
115+
)
116+
self.document_type = ClassificationField(
117+
api_prediction["document_type"],
118+
page_id=page_n,
119+
)
120+
self.due_date = DateField(
121+
api_prediction["due_date"],
122+
page_id=page_n,
123+
)
124+
self.invoice_number = TextField(
125+
api_prediction["invoice_number"],
126+
page_id=page_n,
127+
)
128+
self.line_items = [
129+
FinancialDocumentV1LineItem(prediction, page_id=page_n)
130+
for prediction in api_prediction["line_items"]
104131
]
105132
self.locale = LocaleField(
106-
api_prediction["locale"], value_key="language", page_n=page_n
133+
api_prediction["locale"],
134+
page_id=page_n,
135+
)
136+
self.reference_numbers = [
137+
TextField(prediction, page_id=page_n)
138+
for prediction in api_prediction["reference_numbers"]
139+
]
140+
self.subcategory = ClassificationField(
141+
api_prediction["subcategory"],
142+
page_id=page_n,
107143
)
108-
self.supplier_name = TextField(api_prediction["supplier_name"], page_n=page_n)
109144
self.supplier_address = TextField(
110-
api_prediction["supplier_address"], page_n=page_n
145+
api_prediction["supplier_address"],
146+
page_id=page_n,
111147
)
112-
self.customer_name = TextField(api_prediction["customer_name"], page_n=page_n)
113-
self.customer_company_registrations = [
114-
CompanyRegistrationField(field_dict, page_n=page_n)
115-
for field_dict in api_prediction["customer_company_registrations"]
148+
self.supplier_company_registrations = [
149+
CompanyRegistrationField(prediction, page_id=page_n)
150+
for prediction in api_prediction["supplier_company_registrations"]
116151
]
117-
self.customer_address = TextField(
118-
api_prediction["customer_address"], page_n=page_n
152+
self.supplier_name = TextField(
153+
api_prediction["supplier_name"],
154+
page_id=page_n,
119155
)
120-
self.taxes = Taxes(api_prediction["taxes"], page_id=page_n)
121156
self.supplier_payment_details = [
122-
PaymentDetails(payment_detail, page_n=page_n)
123-
for payment_detail in api_prediction["supplier_payment_details"]
124-
]
125-
self.line_items = [
126-
InvoiceLineItemV4(prediction=line_item, page_n=page_n)
127-
for line_item in api_prediction["line_items"]
157+
PaymentDetails(prediction, page_id=page_n)
158+
for prediction in api_prediction["supplier_payment_details"]
128159
]
129-
self.total_amount = AmountField(api_prediction["total_amount"], page_n=page_n)
130-
self.total_net = AmountField(api_prediction["total_net"], page_n=page_n)
131-
self.total_tax = AmountField(api_prediction["total_tax"], page_n=page_n)
132-
self.tip = AmountField(api_prediction["tip"], page_n=page_n)
133-
self.time = TextField(api_prediction["time"], page_n=page_n)
134-
self.document_type = ClassificationField(
135-
api_prediction["document_type"], page_n=page_n
160+
self.supplier_phone_number = TextField(
161+
api_prediction["supplier_phone_number"],
162+
page_id=page_n,
136163
)
137-
self.category = ClassificationField(api_prediction["category"], page_n=page_n)
138-
self.subcategory = ClassificationField(
139-
api_prediction["subcategory"], page_n=page_n
164+
self.taxes = Taxes(api_prediction["taxes"], page_id=page_n)
165+
self.time = TextField(
166+
api_prediction["time"],
167+
page_id=page_n,
168+
)
169+
self.tip = AmountField(
170+
api_prediction["tip"],
171+
page_id=page_n,
172+
)
173+
self.total_amount = AmountField(
174+
api_prediction["total_amount"],
175+
page_id=page_n,
176+
)
177+
self.total_net = AmountField(
178+
api_prediction["total_net"],
179+
page_id=page_n,
180+
)
181+
self.total_tax = AmountField(
182+
api_prediction["total_tax"],
183+
page_id=page_n,
140184
)
141185

142186
@staticmethod
143-
def _line_items_separator(char: str):
187+
def _line_items_separator(char: str) -> str:
144188
out_str = " "
145189
out_str += f"+{char * 38}"
190+
out_str += f"+{char * 14}"
146191
out_str += f"+{char * 10}"
192+
out_str += f"+{char * 12}"
193+
out_str += f"+{char * 14}"
147194
out_str += f"+{char * 14}"
148195
out_str += f"+{char * 12}"
149196
return out_str + "+"
150197

198+
def _line_items_to_str(self) -> str:
199+
if not self.line_items:
200+
return ""
201+
202+
lines = f"\n{self._line_items_separator('-')}\n ".join(
203+
[item.to_table_line() for item in self.line_items]
204+
)
205+
out_str = ""
206+
out_str += f"\n{self._line_items_separator('-')}\n "
207+
out_str += " | Description "
208+
out_str += " | Product code"
209+
out_str += " | Quantity"
210+
out_str += " | Tax Amount"
211+
out_str += " | Tax Rate (%)"
212+
out_str += " | Total Amount"
213+
out_str += " | Unit Price"
214+
out_str += f" |\n{self._line_items_separator('=')}"
215+
out_str += f"\n {lines}"
216+
out_str += f"\n{self._line_items_separator('-')}"
217+
return out_str
218+
151219
def __str__(self) -> str:
152-
supplier_company_registrations = "; ".join(
153-
[str(n.value) for n in self.supplier_company_registrations]
220+
customer_company_registrations = f"\n { ' ' * 31 }".join(
221+
[str(item) for item in self.customer_company_registrations],
154222
)
155-
customer_company_registrations = "; ".join(
156-
[str(n.value) for n in self.customer_company_registrations]
223+
reference_numbers = f"\n { ' ' * 18 }".join(
224+
[str(item) for item in self.reference_numbers],
157225
)
158-
reference_numbers = ", ".join([str(n.value) for n in self.reference_numbers])
159-
payment_details = "\n ".join(
160-
[str(p) for p in self.supplier_payment_details]
226+
supplier_company_registrations = f"\n { ' ' * 31 }".join(
227+
[str(item) for item in self.supplier_company_registrations],
228+
)
229+
supplier_payment_details = f"\n { ' ' * 25 }".join(
230+
[str(item) for item in self.supplier_payment_details],
161231
)
162-
line_items = "\n"
163-
if self.line_items:
164-
line_items = "\n Code | QTY | Price | Amount | Tax (Rate) | Description\n"
165-
for item in self.line_items:
166-
line_items += f" {item}\n"
167-
168232
return clean_out_string(
169233
"Financial Document V1 Prediction\n"
170234
"================================\n"
171235
f":Filename: {self.filename or ''}\n"
172-
f":Document type: {self.document_type}\n"
173-
f":Category: {self.category}\n"
174-
f":Subcategory: {self.subcategory}\n"
175236
f":Locale: {self.locale}\n"
176-
f":Invoice number: {self.invoice_number}\n"
177-
f":Reference numbers: {reference_numbers}\n"
178-
f":Date: {self.date}\n"
179-
f":Due date: {self.due_date}\n"
180-
f":Time: {self.time}\n"
237+
f":Invoice Number: {self.invoice_number}\n"
238+
f":Reference Numbers: {reference_numbers}\n"
239+
f":Purchase Date: {self.date}\n"
240+
f":Due Date: {self.due_date}\n"
241+
f":Total Net: {self.total_net}\n"
242+
f":Total Amount: {self.total_amount}\n"
243+
f":Taxes: {self.taxes}\n"
244+
f":Supplier Payment Details: {supplier_payment_details}\n"
181245
f":Supplier name: {self.supplier_name}\n"
182-
f":Supplier address: {self.supplier_address}\n"
183-
f":Supplier company registrations: {supplier_company_registrations}\n"
184-
f":Supplier payment details: {payment_details}\n"
246+
f":Supplier Company Registrations: {supplier_company_registrations}\n"
247+
f":Supplier Address: {self.supplier_address}\n"
248+
f":Supplier Phone Number: {self.supplier_phone_number}\n"
185249
f":Customer name: {self.customer_name}\n"
186-
f":Customer address: {self.customer_address}\n"
187-
f":Customer company registrations: {customer_company_registrations}\n"
188-
f":Tip: {self.tip}\n"
189-
f":Taxes: {self.taxes}\n"
190-
f":Total tax: {self.total_tax}\n"
191-
f":Total net: {self.total_net}\n"
192-
f":Total amount: {self.total_amount}\n"
193-
f":Line Items: {line_items}"
250+
f":Customer Company Registrations: {customer_company_registrations}\n"
251+
f":Customer Address: {self.customer_address}\n"
252+
f":Document Type: {self.document_type}\n"
253+
f":Purchase Subcategory: {self.subcategory}\n"
254+
f":Purchase Category: {self.category}\n"
255+
f":Total Tax: {self.total_tax}\n"
256+
f":Tip and Gratuity: {self.tip}\n"
257+
f":Purchase Time: {self.time}\n"
258+
f":Line Items: {self._line_items_to_str()}\n"
194259
)
195260

196-
def _checklist(self) -> None:
197-
pass
198-
199261

200262
TypeFinancialDocumentV1 = TypeVar("TypeFinancialDocumentV1", bound=FinancialDocumentV1)

0 commit comments

Comments
 (0)