mindee 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.yardopts +0 -1
  4. data/CHANGELOG.md +15 -0
  5. data/README.md +13 -9
  6. data/Rakefile +9 -1
  7. data/bin/mindee.rb +8 -0
  8. data/docs/code_samples/bank_account_details_v1.txt +14 -0
  9. data/docs/code_samples/bank_check_v1.txt +14 -0
  10. data/docs/code_samples/carte_vitale_v1.txt +14 -0
  11. data/docs/code_samples/custom_v1.txt +24 -0
  12. data/docs/code_samples/default.txt +16 -0
  13. data/docs/code_samples/expense_receipts_v4.txt +14 -0
  14. data/docs/code_samples/financial_document_v1.txt +14 -0
  15. data/docs/code_samples/idcard_fr_v1.txt +14 -0
  16. data/docs/code_samples/invoices_v4.txt +14 -0
  17. data/docs/code_samples/license_plates_v1.txt +14 -0
  18. data/docs/code_samples/passport_v1.txt +14 -0
  19. data/docs/code_samples/proof_of_address_v1.txt +14 -0
  20. data/docs/code_samples/shipping_containers_v1.txt +14 -0
  21. data/docs/ruby-api-builder.md +35 -42
  22. data/docs/ruby-getting-started.md +2 -2
  23. data/docs/ruby-invoice-ocr.md +12 -13
  24. data/docs/ruby-passport-ocr.md +1 -1
  25. data/docs/ruby-receipt-ocr.md +1 -1
  26. data/lib/mindee/client.rb +34 -30
  27. data/lib/mindee/document_config.rb +15 -23
  28. data/lib/mindee/parsing/prediction/financial_document/financial_document_v1.rb +245 -0
  29. data/lib/mindee/parsing/prediction/financial_document/invoice_line_item.rb +58 -0
  30. data/lib/mindee/parsing/prediction/passport/passport_v1.rb +0 -63
  31. data/lib/mindee/parsing/prediction/proof_of_address/proof_of_address_v1.rb +80 -0
  32. data/lib/mindee/parsing/prediction/receipt/receipt_v4.rb +3 -0
  33. data/lib/mindee/parsing/prediction.rb +2 -0
  34. data/lib/mindee/version.rb +1 -1
  35. data/mindee.gemspec +2 -3
  36. metadata +24 -22
data/lib/mindee/client.rb CHANGED
@@ -23,8 +23,8 @@ module Mindee
23
23
  # API Builder. Do not set for standard (off the shelf) endpoints.
24
24
  #
25
25
  # @param account_name [String] For custom endpoints, your account or organization username on the API Builder.
26
- # This is normally not required unless you have a custom endpoint which has the
27
- # same name as standard (off the shelf) endpoint.
26
+ # This is normally not required unless you have a custom endpoint which has the same name as a
27
+ # standard (off the shelf) endpoint.
28
28
  # Do not set for standard (off the shelf) endpoints.
29
29
  #
30
30
  # @param include_words [Boolean] Whether to include the full text for each page.
@@ -121,7 +121,7 @@ module Mindee
121
121
  )
122
122
  @doc_configs[[account_name, endpoint_name]] = DocumentConfig.new(
123
123
  Prediction::CustomV1,
124
- [HTTP::CustomEndpoint.new(account_name, endpoint_name, version, @api_key)]
124
+ HTTP::CustomEndpoint.new(account_name, endpoint_name, version, @api_key)
125
125
  )
126
126
  self
127
127
  end
@@ -163,42 +163,46 @@ module Mindee
163
163
 
164
164
  private
165
165
 
166
+ def standard_document_config(prediction_class, endpoint_name, version)
167
+ DocumentConfig.new(
168
+ prediction_class,
169
+ HTTP::StandardEndpoint.new(endpoint_name, version, @api_key)
170
+ )
171
+ end
172
+
166
173
  def init_default_endpoints
167
- @doc_configs[['mindee', Prediction::InvoiceV4.name]] = DocumentConfig.new(
168
- Prediction::InvoiceV4,
169
- [HTTP::StandardEndpoint.new('invoices', '4', @api_key)]
174
+ @doc_configs[['mindee', Prediction::ProofOfAddressV1.name]] = standard_document_config(
175
+ Prediction::ProofOfAddressV1, 'proof_of_address', '1'
176
+ )
177
+ @doc_configs[['mindee', Prediction::FinancialDocumentV1.name]] = standard_document_config(
178
+ Prediction::FinancialDocumentV1, 'financial_document', '1'
179
+ )
180
+ @doc_configs[['mindee', Prediction::InvoiceV4.name]] = standard_document_config(
181
+ Prediction::InvoiceV4, 'invoices', '4'
170
182
  )
171
- @doc_configs[['mindee', Prediction::ReceiptV4.name]] = DocumentConfig.new(
172
- Prediction::ReceiptV4,
173
- [HTTP::StandardEndpoint.new('expense_receipts', '4', @api_key)]
183
+ @doc_configs[['mindee', Prediction::ReceiptV4.name]] = standard_document_config(
184
+ Prediction::ReceiptV4, 'expense_receipts', '4'
174
185
  )
175
- @doc_configs[['mindee', Prediction::PassportV1.name]] = DocumentConfig.new(
176
- Prediction::PassportV1,
177
- [HTTP::StandardEndpoint.new('passport', '1', @api_key)]
186
+ @doc_configs[['mindee', Prediction::PassportV1.name]] = standard_document_config(
187
+ Prediction::PassportV1, 'passport', '1'
178
188
  )
179
- @doc_configs[['mindee', Prediction::EU::LicensePlateV1.name]] = DocumentConfig.new(
180
- Prediction::EU::LicensePlateV1,
181
- [HTTP::StandardEndpoint.new('license_plates', '1', @api_key)]
189
+ @doc_configs[['mindee', Prediction::EU::LicensePlateV1.name]] = standard_document_config(
190
+ Prediction::EU::LicensePlateV1, 'license_plates', '1'
182
191
  )
183
- @doc_configs[['mindee', Prediction::ShippingContainerV1.name]] = DocumentConfig.new(
184
- Prediction::ShippingContainerV1,
185
- [HTTP::StandardEndpoint.new('shipping_containers', '1', @api_key)]
192
+ @doc_configs[['mindee', Prediction::ShippingContainerV1.name]] = standard_document_config(
193
+ Prediction::ShippingContainerV1, 'shipping_containers', '1'
186
194
  )
187
- @doc_configs[['mindee', Prediction::US::BankCheckV1.name]] = DocumentConfig.new(
188
- Prediction::US::BankCheckV1,
189
- [HTTP::StandardEndpoint.new('bank_check', '1', @api_key)]
195
+ @doc_configs[['mindee', Prediction::US::BankCheckV1.name]] = standard_document_config(
196
+ Prediction::US::BankCheckV1, 'bank_check', '1'
190
197
  )
191
- @doc_configs[['mindee', Prediction::FR::BankAccountDetailsV1.name]] = DocumentConfig.new(
192
- Prediction::FR::BankAccountDetailsV1,
193
- [HTTP::StandardEndpoint.new('bank_account_details', '1', @api_key)]
198
+ @doc_configs[['mindee', Prediction::FR::BankAccountDetailsV1.name]] = standard_document_config(
199
+ Prediction::FR::BankAccountDetailsV1, 'bank_account_details', '1'
194
200
  )
195
- @doc_configs[['mindee', Prediction::FR::CarteVitaleV1.name]] = DocumentConfig.new(
196
- Prediction::FR::CarteVitaleV1,
197
- [HTTP::StandardEndpoint.new('carte_vitale', '1', @api_key)]
201
+ @doc_configs[['mindee', Prediction::FR::CarteVitaleV1.name]] = standard_document_config(
202
+ Prediction::FR::CarteVitaleV1, 'carte_vitale', '1'
198
203
  )
199
- @doc_configs[['mindee', Prediction::FR::IdCardV1.name]] = DocumentConfig.new(
200
- Prediction::FR::IdCardV1,
201
- [HTTP::StandardEndpoint.new('idcard_fr', '1', @api_key)]
204
+ @doc_configs[['mindee', Prediction::FR::IdCardV1.name]] = standard_document_config(
205
+ Prediction::FR::IdCardV1, 'idcard_fr', '1'
202
206
  )
203
207
  self
204
208
  end
@@ -11,14 +11,14 @@ module Mindee
11
11
  # Specific client for sending a document to the API.
12
12
  class DocumentConfig
13
13
  # Array of possible Mindee::Endpoint to be used.
14
- # @return [Array<Mindee::HTTP::Endpoint>]
15
- attr_reader :endpoints
14
+ # @return [Mindee::HTTP::Endpoint]
15
+ attr_reader :endpoint
16
16
 
17
17
  # @param prediction_class [Class<Mindee::Prediction::Prediction>]
18
- # @param endpoints [Array<Mindee::HTTP::Endpoint>]
19
- def initialize(prediction_class, endpoints)
18
+ # @param endpoint [Mindee::HTTP::Endpoint]
19
+ def initialize(prediction_class, endpoint)
20
20
  @prediction_class = prediction_class
21
- @endpoints = endpoints
21
+ @endpoint = endpoint
22
22
  end
23
23
 
24
24
  # Call the prediction API.
@@ -28,16 +28,8 @@ module Mindee
28
28
  # @param cropper [Boolean]
29
29
  # @return [Mindee::DocumentResponse]
30
30
  def predict(input_doc, include_words, close_file, cropper)
31
- check_api_keys
31
+ check_api_key
32
32
  response = predict_request(input_doc, include_words, close_file, cropper)
33
- parse_response(response)
34
- end
35
-
36
- private
37
-
38
- # @param response [Net::HTTPResponse]
39
- # @return [Mindee::DocumentResponse]
40
- def parse_response(response)
41
33
  hashed_response = JSON.parse(response.body, object_class: Hash)
42
34
  return Document.new(@prediction_class, hashed_response['document']) if (200..299).include?(response.code.to_i)
43
35
 
@@ -45,24 +37,24 @@ module Mindee
45
37
  raise error
46
38
  end
47
39
 
40
+ private
41
+
48
42
  # @param input_doc [Mindee::InputDocument]
49
43
  # @param include_words [Boolean]
50
44
  # @param close_file [Boolean]
51
45
  # # @param cropper [Boolean]
52
46
  # @return [Net::HTTPResponse]
53
47
  def predict_request(input_doc, include_words, close_file, cropper)
54
- @endpoints[0].predict_req_post(input_doc, include_words: include_words, close_file: close_file, cropper: cropper)
48
+ @endpoint.predict_req_post(input_doc, include_words: include_words, close_file: close_file, cropper: cropper)
55
49
  end
56
50
 
57
- def check_api_keys
58
- @endpoints.each do |endpoint|
59
- next unless endpoint.api_key.nil? || endpoint.api_key.empty?
51
+ def check_api_key
52
+ return unless @endpoint.api_key.nil? || @endpoint.api_key.empty?
60
53
 
61
- raise "Missing API key for '#{@document_type}', " \
62
- "check your Client Configuration.\n" \
63
- 'You can set this using the ' \
64
- "'#{HTTP::API_KEY_ENV_NAME}' environment variable."
65
- end
54
+ raise "Missing API key for '#{@document_type}', " \
55
+ "check your Client Configuration.\n" \
56
+ 'You can set this using the ' \
57
+ "'#{HTTP::API_KEY_ENV_NAME}' environment variable."
66
58
  end
67
59
  end
68
60
  end
@@ -0,0 +1,245 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../common_fields'
4
+ require_relative '../base'
5
+ require_relative 'invoice_line_item'
6
+
7
+ module Mindee
8
+ module Prediction
9
+ # Invoice document.
10
+ class FinancialDocumentV1 < Prediction
11
+ # Locale information.
12
+ # @return [Mindee::Locale]
13
+ attr_reader :locale
14
+ # The nature of the document.
15
+ # @return [Mindee::TextField]
16
+ attr_reader :document_type
17
+ # The total amount with tax included.
18
+ # @return [Mindee::AmountField]
19
+ attr_reader :total_amount
20
+ # The total amount without the tax value.
21
+ # @return [Mindee::AmountField]
22
+ attr_reader :total_net
23
+ # The total tax.
24
+ # @return [Mindee::AmountField]
25
+ attr_reader :total_tax
26
+ # The creation date of the document.
27
+ # @return [Mindee::DateField]
28
+ attr_reader :date
29
+ # The invoice number.
30
+ # @return [Mindee::TextField]
31
+ attr_reader :invoice_number
32
+ # List of Reference numbers including PO number.
33
+ # @return [Mindee::TextField]
34
+ attr_reader :reference_numbers
35
+ # The due date of the invoice.
36
+ # @return [Mindee::DateField]
37
+ attr_reader :due_date
38
+ # The list of taxes.
39
+ # @return [Array<Mindee::TaxField>]
40
+ attr_reader :taxes
41
+ # The name of the customer.
42
+ # @return [Mindee::TextField]
43
+ attr_reader :customer_name
44
+ # The address of the customer.
45
+ # @return [Mindee::TextField]
46
+ attr_reader :customer_address
47
+ # The company registration information for the customer.
48
+ # @return [Array<Mindee::CompanyRegistration>]
49
+ attr_reader :customer_company_registrations
50
+ # The supplier's name.
51
+ # @return [Mindee::TextField]
52
+ attr_reader :supplier_name
53
+ # The supplier's address.
54
+ # @return [Mindee::TextField]
55
+ attr_reader :supplier_address
56
+ # The supplier's payment information.
57
+ # @return [Array<Mindee::PaymentDetails>]
58
+ attr_reader :supplier_payment_details
59
+ # The supplier's company registration information.
60
+ # @return [Array<Mindee::CompanyRegistration>]
61
+ attr_reader :supplier_company_registrations
62
+ # Line items details.
63
+ # @return [Array<Mindee::InvoiceLineItem>]
64
+ attr_reader :line_items
65
+ # Time as seen on the receipt in HH:MM format.
66
+ # @return [Mindee::TextField]
67
+ attr_reader :time
68
+ # The invoice or receipt category among predefined classes.
69
+ # @return [Mindee::TextField]
70
+ attr_reader :category
71
+ # The invoice or receipt sub-category among predefined classes.
72
+ # @return [Mindee::TextField]
73
+ attr_reader :subcategory
74
+ # A classification field, that can return 4 values:
75
+ # `EXPENSE RECEIPT`, `CREDIT CARD RECEIPT`, `INVOICE`, `CREDIT NOTE`
76
+ # @return [Mindee::TextField]
77
+ attr_reader :document_type # rubocop:todo Lint/DuplicateMethods
78
+ # Total amount of tip and gratuity. Both typed and handwritten characters are supported.
79
+ # @return [Mindee::AmountField]
80
+ attr_reader :tip
81
+
82
+ # @param prediction [Hash]
83
+ # @param page_id [Integer, nil]
84
+ def initialize(prediction, page_id) # rubocop:todo Metrics/AbcSize
85
+ super
86
+
87
+ @time = TextField.new(prediction['time'], page_id)
88
+ @category = TextField.new(prediction['category'], page_id)
89
+ @subcategory = TextField.new(prediction['subcategory'], page_id)
90
+ @document_type = TextField.new(prediction['document_type'], page_id)
91
+ @tip = AmountField.new(prediction['tip'], page_id)
92
+ @locale = Locale.new(prediction['locale'])
93
+ @document_type = TextField.new(prediction['document_type'], page_id)
94
+ @total_amount = AmountField.new(prediction['total_amount'], page_id)
95
+ @total_net = AmountField.new(prediction['total_net'], page_id)
96
+ @customer_address = TextField.new(prediction['customer_address'], page_id)
97
+ @customer_name = TextField.new(prediction['customer_name'], page_id)
98
+ @date = DateField.new(prediction['date'], page_id)
99
+ @due_date = DateField.new(prediction['due_date'], page_id)
100
+ @invoice_number = TextField.new(prediction['invoice_number'], page_id)
101
+ @supplier_name = TextField.new(prediction['supplier_name'], page_id)
102
+ @supplier_address = TextField.new(prediction['supplier_address'], page_id)
103
+
104
+ @reference_numbers = []
105
+ prediction['reference_numbers'].each do |item|
106
+ @reference_numbers.push(TextField.new(item, page_id))
107
+ end
108
+ @customer_company_registrations = []
109
+ prediction['customer_company_registrations'].each do |item|
110
+ @customer_company_registrations.push(CompanyRegistration.new(item, page_id))
111
+ end
112
+ @taxes = []
113
+ prediction['taxes'].each do |item|
114
+ @taxes.push(TaxField.new(item, page_id))
115
+ end
116
+ @supplier_payment_details = []
117
+ prediction['supplier_payment_details'].each do |item|
118
+ @supplier_payment_details.push(PaymentDetails.new(item, page_id))
119
+ end
120
+ @supplier_company_registrations = []
121
+ prediction['supplier_company_registrations'].each do |item|
122
+ @supplier_company_registrations.push(CompanyRegistration.new(item, page_id))
123
+ end
124
+
125
+ @total_tax = AmountField.new(
126
+ { value: nil, confidence: 0.0 }, page_id
127
+ )
128
+
129
+ @line_items = []
130
+ prediction['line_items'].each do |item|
131
+ @line_items.push(InvoiceLineItem.new(item, page_id))
132
+ end
133
+ reconstruct(page_id)
134
+ end
135
+
136
+ def to_s
137
+ customer_company_registrations = @customer_company_registrations.map(&:value).join('; ')
138
+ supplier_payment_details = @supplier_payment_details.map(&:to_s).join("\n ")
139
+ supplier_company_registrations = @supplier_company_registrations.map(&:to_s).join('; ')
140
+ reference_numbers = @reference_numbers.map(&:to_s).join(', ')
141
+ taxes = @taxes.join("\n ")
142
+ out_str = String.new
143
+ out_str << "\n:Document type: #{@document_type}".rstrip
144
+ out_str << "\n:Category: #{@category}".rstrip
145
+ out_str << "\n:Subcategory: #{@subcategory}".rstrip
146
+ out_str << "\n:Locale: #{@locale}".rstrip
147
+ out_str << "\n:Date: #{@date}".rstrip
148
+ out_str << "\n:Due date: #{@due_date}".rstrip
149
+ out_str << "\n:Time: #{@time}".rstrip
150
+ out_str << "\n:Number: #{@invoice_number}".rstrip
151
+ out_str << "\n:Reference numbers: #{reference_numbers}".rstrip
152
+ out_str << "\n:Supplier name: #{@supplier_name}".rstrip
153
+ out_str << "\n:Supplier address: #{@supplier_address}".rstrip
154
+ out_str << "\n:Supplier company registrations: #{supplier_company_registrations}".rstrip
155
+ out_str << "\n:Supplier payment details: #{supplier_payment_details}".rstrip
156
+
157
+ out_str << "\n:Customer name: #{@customer_name}".rstrip
158
+ out_str << "\n:Customer address: #{@customer_address}".rstrip
159
+ out_str << "\n:Customer company registrations: #{customer_company_registrations}".rstrip
160
+
161
+ out_str << "\n:Tip: #{@tip}".rstrip
162
+
163
+ out_str << "\n:Taxes: #{taxes}".rstrip
164
+ out_str << "\n:Total taxes: #{@total_tax}".rstrip
165
+ out_str << "\n:Total net: #{@total_net}".rstrip
166
+ out_str << "\n:Total amount: #{@total_amount}".rstrip
167
+
168
+ out_str << line_items_to_s
169
+
170
+ out_str[1..].to_s
171
+ end
172
+
173
+ private
174
+
175
+ def line_items_to_s
176
+ line_item_separator = "#{'=' * 22} #{'=' * 8} #{'=' * 9} #{'=' * 10} #{'=' * 18} #{'=' * 36}"
177
+ line_items = @line_items.map(&:to_s).join("\n")
178
+
179
+ out_str = String.new
180
+ out_str << "\n\n:Line Items:"
181
+
182
+ return out_str if line_items.empty?
183
+
184
+ out_str << "\n#{line_item_separator}"
185
+ out_str << "\nCode QTY Price Amount Tax (Rate) Description"
186
+ out_str << "\n#{line_item_separator}"
187
+ out_str << "\n#{line_items}"
188
+ out_str << "\n#{line_item_separator}"
189
+ end
190
+
191
+ def reconstruct(page_id)
192
+ construct_total_tax_from_taxes(page_id)
193
+ return unless page_id.nil?
194
+
195
+ construct_total_excl_from_tcc_and_taxes(page_id)
196
+ construct_total_incl_from_taxes_plus_excl(page_id)
197
+ construct_total_tax_from_totals(page_id)
198
+ end
199
+
200
+ def construct_total_excl_from_tcc_and_taxes(page_id)
201
+ return if @total_amount.value.nil? || taxes.empty? || !@total_net.value.nil?
202
+
203
+ total_excl = {
204
+ 'value' => @total_amount.value - @taxes.map(&:value).sum,
205
+ 'confidence' => TextField.array_confidence(@taxes) * @total_amount.confidence,
206
+ }
207
+ @total_net = AmountField.new(total_excl, page_id, reconstructed: true)
208
+ end
209
+
210
+ def construct_total_incl_from_taxes_plus_excl(page_id)
211
+ return if @total_net.value.nil? || @taxes.empty? || !@total_amount.value.nil?
212
+
213
+ total_incl = {
214
+ 'value' => @taxes.map(&:value).sum + @total_net.value,
215
+ 'confidence' => TextField.array_confidence(@taxes) * @total_net.confidence,
216
+ }
217
+ @total_amount = AmountField.new(total_incl, page_id, reconstructed: true)
218
+ end
219
+
220
+ def construct_total_tax_from_taxes(page_id)
221
+ return if @taxes.empty?
222
+
223
+ total_tax = {
224
+ 'value' => @taxes.map(&:value).sum,
225
+ 'confidence' => TextField.array_confidence(@taxes),
226
+ }
227
+ return unless total_tax['value'].positive?
228
+
229
+ @total_tax = AmountField.new(total_tax, page_id, reconstructed: true)
230
+ end
231
+
232
+ def construct_total_tax_from_totals(page_id)
233
+ return if !@total_tax.value.nil? || @total_amount.value.nil? || @total_net.value.nil?
234
+
235
+ total_tax = {
236
+ 'value' => @total_amount.value - @total_net.value,
237
+ 'confidence' => TextField.array_confidence(@taxes),
238
+ }
239
+ return unless total_tax['value'] >= 0
240
+
241
+ @total_tax = AmountField.new(total_tax, page_id, reconstructed: true)
242
+ end
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../common_fields/base'
4
+
5
+ module Mindee
6
+ # Line items for invoices
7
+ class InvoiceLineItem
8
+ # @return [String] The product code referring to the item.
9
+ attr_reader :product_code
10
+ # @return [String]
11
+ attr_reader :description
12
+ # @return [Float]
13
+ attr_reader :quantity
14
+ # @return [Float]
15
+ attr_reader :unit_price
16
+ # @return [Float]
17
+ attr_reader :total_amount
18
+ # @return [Float] The item tax rate percentage.
19
+ attr_reader :tax_rate
20
+ # @return [Float]
21
+ attr_reader :tax_amount
22
+ # @return [Float]
23
+ attr_reader :confidence
24
+ # @return [Integer]
25
+ attr_reader :page_id
26
+ # @return [Mindee::Geometry::Quadrilateral]
27
+ attr_reader :bounding_box
28
+ # @return [Array<Mindee::Geometry::Polygon>]
29
+ attr_reader :polygon
30
+
31
+ def initialize(prediction, page_id)
32
+ @product_code = prediction['product_code']
33
+ @quantity = prediction['quantity']
34
+ @unit_price = prediction['unit_price']
35
+ @total_amount = prediction['total_amount']
36
+ @tax_amount = prediction['tax_amount']
37
+ @tax_rate = prediction['tax_rate']
38
+ @description = prediction['description']
39
+ @page_id = page_id
40
+ end
41
+
42
+ def to_s
43
+ tax = Field.float_to_string(@tax_amount)
44
+ tax << " (#{Field.float_to_string(@tax_rate)}%)" unless @tax_rate.nil?
45
+
46
+ description = @description.nil? ? '' : @description
47
+ description = "#{description[0..32]}..." if description.size > 35
48
+
49
+ out_str = String.new
50
+ out_str << format('%- 22s', @product_code)
51
+ out_str << " #{format('%- 8s', Field.float_to_string(@quantity))}"
52
+ out_str << " #{format('%- 9s', Field.float_to_string(@unit_price))}"
53
+ out_str << " #{format('%- 10s', Field.float_to_string(@total_amount))}"
54
+ out_str << " #{format('%- 18s', tax)}"
55
+ out_str << " #{description}"
56
+ end
57
+ end
58
+ end
@@ -1,19 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'mrz'
4
-
5
3
  require_relative '../common_fields'
6
4
  require_relative '../base'
7
5
 
8
- # We need to do this disgusting thing to avoid the following error message:
9
- # td3 line one does not match the required format (MRZ::InvalidFormatError)
10
- #
11
- # See:
12
- # https://github.com/streetspotr/mrz/issues/2
13
- # https://github.com/streetspotr/mrz/pull/3
14
- #
15
- MRZ::TD3Parser::FORMAT_ONE = %r{\A(.{2})(.{3})([^<]+)<(.*)\z}.freeze
16
-
17
6
  module Mindee
18
7
  module Prediction
19
8
  # Passport document.
@@ -78,7 +67,6 @@ module Mindee
78
67
  end
79
68
  @full_name = construct_full_name(page_id)
80
69
  @mrz = construct_mrz(page_id)
81
- check_mrz
82
70
  end
83
71
 
84
72
  def to_s
@@ -107,57 +95,6 @@ module Mindee
107
95
 
108
96
  private
109
97
 
110
- def check_mrz
111
- return if @mrz1.value.nil? || @mrz2.value.nil?
112
-
113
- mrz = MRZ.parse([@mrz1.value, @mrz2.value])
114
- checks = {
115
- mrz_valid: valid_mrz?(mrz),
116
- mrz_valid_birth_date: valid_birth_date?(mrz),
117
- mrz_valid_expiry_date: valid_expiry_date?(mrz),
118
- mrz_valid_id_number: valid_id_number?(mrz),
119
- mrz_valid_surname: valid_surname?(mrz),
120
- mrz_valid_country: valid_country?(mrz),
121
- }
122
- @checklist.merge!(checks)
123
- end
124
-
125
- def valid_mrz?(mrz)
126
- check = mrz.valid?
127
- @mrz.confidence = 1.0 if check
128
- check
129
- end
130
-
131
- def valid_birth_date?(mrz)
132
- check = mrz.valid_birth_date? && mrz.birth_date == @birth_date.date_object
133
- @birth_date.confidence = 1.0 if check
134
- check
135
- end
136
-
137
- def valid_expiry_date?(mrz)
138
- check = mrz.valid_expiration_date? && mrz.expiration_date == @expiry_date.date_object
139
- @expiry_date.confidence = 1.0 if check
140
- check
141
- end
142
-
143
- def valid_id_number?(mrz)
144
- check = mrz.valid_document_number? && mrz.document_number == @id_number.value
145
- @id_number.confidence = 1.0 if check
146
- check
147
- end
148
-
149
- def valid_surname?(mrz)
150
- check = mrz.last_name == @surname.value
151
- @surname.confidence = 1.0 if check
152
- check
153
- end
154
-
155
- def valid_country?(mrz)
156
- check = mrz.nationality == @country.value
157
- @country.confidence = 1.0 if check
158
- check
159
- end
160
-
161
98
  def construct_full_name(page_id)
162
99
  return unless @surname.value &&
163
100
  !@given_names.empty? &&
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../common_fields'
4
+ require_relative '../base'
5
+
6
+ module Mindee
7
+ module Prediction
8
+ # Passport document.
9
+ class ProofOfAddressV1 < Prediction
10
+ # ISO 639-1 code, works best with ca, de, en, es, fr, it, nl and pt.
11
+ # @return [Mindee::Locale]
12
+ attr_reader :locale
13
+ # ISO date yyyy-mm-dd. Works both for European and US dates.
14
+ # @return [Mindee::DateField]
15
+ attr_reader :date
16
+ # All extracted ISO date yyyy-mm-dd. Works both for European and US dates.
17
+ # @return [Array<Mindee::DateField>]
18
+ attr_reader :dates
19
+ # Address of the document's issuer.
20
+ # @return [Mindee::TextField]
21
+ attr_reader :issuer_address
22
+ # Generic: VAT NUMBER, TAX ID, COMPANY REGISTRATION NUMBER or country specific.
23
+ # @return [Array<Mindee::CompanyRegistration>]
24
+ attr_reader :issuer_company_registration
25
+ # Name of the person or company issuing the document.
26
+ # @return [Mindee::TextField]
27
+ attr_reader :issuer_name
28
+ # Address of the recipient.
29
+ # @return [Mindee::TextField]
30
+ attr_reader :recipient_address
31
+ # Generic: VAT NUMBER, TAX ID, COMPANY REGISTRATION NUMBER or country specific.
32
+ # @return [Array<Mindee::CompanyRegistration>]
33
+ attr_reader :recipient_company_registration
34
+ # Name of the document's recipient.
35
+ # @return [Mindee::TextField]
36
+ attr_reader :recipient_name
37
+
38
+ # @param prediction [Hash]
39
+ # @param page_id [Integer, nil]
40
+ def initialize(prediction, page_id)
41
+ super
42
+ @locale = Locale.new(prediction['locale'])
43
+ @date = DateField.new(prediction['date'], page_id)
44
+ @dates = []
45
+ prediction['dates'].each do |item|
46
+ @dates.push(DateField.new(item, page_id))
47
+ end
48
+ @issuer_name = TextField.new(prediction['issuer_name'], page_id)
49
+ @issuer_address = TextField.new(prediction['issuer_address'], page_id)
50
+ @issuer_company_registration = []
51
+ prediction['issuer_company_registration'].each do |item|
52
+ @issuer_company_registration.push(CompanyRegistration.new(item, page_id))
53
+ end
54
+ @recipient_name = TextField.new(prediction['recipient_name'], page_id)
55
+ @recipient_address = TextField.new(prediction['recipient_address'], page_id)
56
+ @recipient_company_registration = []
57
+ prediction['recipient_company_registration'].each do |item|
58
+ @recipient_company_registration.push(CompanyRegistration.new(item, page_id))
59
+ end
60
+ end
61
+
62
+ def to_s
63
+ recipient_company_registrations = @recipient_company_registration.join(' ')
64
+ issuer_company_registrations = @issuer_company_registration.join(' ')
65
+ dates = @dates.join("\n ")
66
+ out_str = String.new
67
+ out_str << "\n:Locale: #{@locale}".rstrip
68
+ out_str << "\n:Issuer name: #{@issuer_name}".rstrip
69
+ out_str << "\n:Issuer Address: #{@issuer_address}".rstrip
70
+ out_str << "\n:Issuer Company Registrations: #{issuer_company_registrations}".rstrip
71
+ out_str << "\n:Recipient name: #{@recipient_name}".rstrip
72
+ out_str << "\n:Recipient Address: #{@recipient_address}".rstrip
73
+ out_str << "\n:Recipient Company Registrations: #{recipient_company_registrations}".rstrip
74
+ out_str << "\n:Issuance date: #{@date}".rstrip
75
+ out_str << "\n:Dates: #{dates}".rstrip
76
+ out_str[1..].to_s
77
+ end
78
+ end
79
+ end
80
+ end
@@ -40,6 +40,9 @@ module Mindee
40
40
  # Whether the document is an expense receipt or a credit card receipt.
41
41
  # @return [Mindee::TextField]
42
42
  attr_reader :document_type
43
+ # Total amount of tip and gratuity. Both typed and handwritten characters are supported.
44
+ # @return [Mindee::AmountField]
45
+ attr_reader :tip
43
46
 
44
47
  # @param prediction [Hash]
45
48
  # @param page_id [Integer, nil]
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'prediction/custom/custom_v1'
4
+ require_relative 'prediction/proof_of_address/proof_of_address_v1'
5
+ require_relative 'prediction/financial_document/financial_document_v1'
4
6
  require_relative 'prediction/invoice/invoice_v4'
5
7
  require_relative 'prediction/passport/passport_v1'
6
8
  require_relative 'prediction/receipt/receipt_v4'
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Mindee
4
4
  module Mindee
5
- VERSION = '2.0.0'
5
+ VERSION = '2.1.1'
6
6
 
7
7
  def self.find_platform
8
8
  host = RbConfig::CONFIG['host_os']