mindee 1.0.0

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.
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../fields'
4
+ require_relative 'base'
5
+
6
+ module Mindee
7
+ # Invoice document.
8
+ class Invoice < Document
9
+ # @return [Mindee::Locale]
10
+ attr_reader :locale
11
+ # @return [Mindee::Amount]
12
+ attr_reader :total_incl
13
+ # @return [Mindee::Amount]
14
+ attr_reader :total_excl
15
+ # @return [Mindee::Amount]
16
+ attr_reader :total_tax
17
+ # @return [Mindee::DateField]
18
+ attr_reader :date
19
+ # @return [Mindee::Field]
20
+ attr_reader :invoice_number
21
+ # @return [Mindee::DateField]
22
+ attr_reader :due_date
23
+ # @return [Array<Mindee::TaxField>]
24
+ attr_reader :taxes
25
+ # @return [Array<Mindee::CompanyRegistration>]
26
+ attr_reader :customer_company_registration
27
+ # @return [Array<Mindee::PaymentDetails>]
28
+ attr_reader :payment_details
29
+ # @return [Array<Mindee::CompanyRegistration>]
30
+ attr_reader :company_registration
31
+ # @return [Mindee::Field]
32
+ attr_reader :customer_name
33
+ # @return [Mindee::Field]
34
+ attr_reader :supplier
35
+ # @return [Mindee::Field]
36
+ attr_reader :supplier_address
37
+ # @return [Mindee::Field]
38
+ attr_reader :customer_address
39
+ # @return [Mindee::Orientation]
40
+ attr_reader :orientation
41
+
42
+ # @param prediction [Hash]
43
+ # @param input_file [Mindee::InputDocument, nil]
44
+ # @param page_id [Integer, nil]
45
+ def initialize(prediction, input_file: nil, page_id: nil)
46
+ super('invoice', input_file: input_file)
47
+ @orientation = Orientation.new(prediction['orientation'], page_id) if page_id
48
+ @locale = Locale.new(prediction['locale'])
49
+ @total_incl = Amount.new(prediction['total_incl'], page_id)
50
+ @total_excl = Amount.new(prediction['total_excl'], page_id)
51
+ @customer_address = Field.new(prediction['customer_address'], page_id)
52
+ @customer_name = Field.new(prediction['customer'], page_id)
53
+ @date = DateField.new(prediction['date'], page_id)
54
+ @due_date = DateField.new(prediction['due_date'], page_id)
55
+ @invoice_number = Field.new(prediction['invoice_number'], page_id)
56
+ @supplier = Field.new(prediction['supplier'], page_id)
57
+ @supplier_address = Field.new(prediction['supplier_address'], page_id)
58
+
59
+ @customer_company_registration = []
60
+ prediction['customer_company_registration'].each do |item|
61
+ @customer_company_registration.push(CompanyRegistration.new(item, page_id))
62
+ end
63
+ @taxes = []
64
+ prediction['taxes'].each do |item|
65
+ @taxes.push(TaxField.new(item, page_id))
66
+ end
67
+ @payment_details = []
68
+ prediction['payment_details'].each do |item|
69
+ @payment_details.push(PaymentDetails.new(item, page_id))
70
+ end
71
+ @company_registration = []
72
+ prediction['company_registration'].each do |item|
73
+ @company_registration.push(CompanyRegistration.new(item, page_id))
74
+ end
75
+
76
+ @total_tax = Amount.new(
77
+ { value: nil, confidence: 0.0 }, page_id
78
+ )
79
+ reconstruct(page_id)
80
+ end
81
+
82
+ def to_s
83
+ customer_company_registration = @customer_company_registration.map(&:value).join('; ')
84
+ payment_details = @payment_details.map(&:to_s).join("\n ")
85
+ company_registration = @company_registration.map(&:to_s).join('; ')
86
+ taxes = @taxes.join("\n ")
87
+ out_str = String.new
88
+ out_str << '-----Invoice data-----'
89
+ out_str << "\nFilename: #{@filename}".rstrip
90
+ out_str << "\nInvoice number: #{@invoice_number}".rstrip
91
+ out_str << "\nTotal amount including taxes: #{@total_incl}".rstrip
92
+ out_str << "\nTotal amount excluding taxes: #{@total_excl}".rstrip
93
+ out_str << "\nInvoice date: #{@date}".rstrip
94
+ out_str << "\nInvoice due date: #{@due_date}".rstrip
95
+ out_str << "\nSupplier name: #{@supplier}".rstrip
96
+ out_str << "\nSupplier address: #{@supplier_address}".rstrip
97
+ out_str << "\nCustomer name: #{@customer_name}".rstrip
98
+ out_str << "\nCustomer company registration: #{customer_company_registration}".rstrip
99
+ out_str << "\nCustomer address: #{@customer_address}".rstrip
100
+ out_str << "\nPayment details: #{payment_details}".rstrip
101
+ out_str << "\nCompany numbers: #{company_registration}".rstrip
102
+ out_str << "\nTaxes: #{taxes}".rstrip
103
+ out_str << "\nTotal taxes: #{@total_tax}".rstrip
104
+ out_str << "\nLocale: #{@locale}".rstrip
105
+ out_str << "\n----------------------"
106
+ out_str
107
+ end
108
+
109
+ private
110
+
111
+ def reconstruct(page_id)
112
+ construct_total_tax_from_taxes(page_id)
113
+ construct_total_excl_from_tcc_and_taxes(page_id)
114
+ construct_total_incl_from_taxes_plus_excl(page_id)
115
+ construct_total_tax_from_totals(page_id)
116
+ end
117
+
118
+ def construct_total_excl_from_tcc_and_taxes(page_id)
119
+ return if @total_incl.value.nil? || taxes.empty? || !@total_excl.value.nil?
120
+
121
+ total_excl = {
122
+ 'value' => @total_incl.value - @taxes.map(&:value).sum,
123
+ 'confidence' => Field.array_confidence(@taxes) * @total_incl.confidence,
124
+ }
125
+ @total_excl = Amount.new(total_excl, page_id, reconstructed: true)
126
+ end
127
+
128
+ def construct_total_incl_from_taxes_plus_excl(page_id)
129
+ return if @total_excl.value.nil? || @taxes.empty? || !@total_incl.value.nil?
130
+
131
+ total_incl = {
132
+ 'value' => @taxes.map(&:value).sum + @total_excl.value,
133
+ 'confidence' => Field.array_confidence(@taxes) * @total_excl.confidence,
134
+ }
135
+ @total_incl = Amount.new(total_incl, page_id, reconstructed: true)
136
+ end
137
+
138
+ def construct_total_tax_from_taxes(page_id)
139
+ return if @taxes.empty?
140
+
141
+ total_tax = {
142
+ 'value' => @taxes.map(&:value).sum,
143
+ 'confidence' => Field.array_confidence(@taxes),
144
+ }
145
+ return unless total_tax['value'].positive?
146
+
147
+ @total_tax = Amount.new(total_tax, page_id, reconstructed: true)
148
+ end
149
+
150
+ def construct_total_tax_from_totals(page_id)
151
+ return if !@total_tax.value.nil? || @total_incl.value.nil? || @total_excl.value.nil?
152
+
153
+ total_tax = {
154
+ 'value' => @total_incl.value - @total_excl.value,
155
+ 'confidence' => Field.array_confidence(@taxes),
156
+ }
157
+ return unless total_tax['value'] >= 0
158
+
159
+ @total_tax = Amount.new(total_tax, page_id, reconstructed: true)
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mrz'
4
+
5
+ require_relative '../fields'
6
+ require_relative 'base'
7
+
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
+ module Mindee
18
+ # Passport document.
19
+ class Passport < Document
20
+ # @return [Mindee::Orientation]
21
+ attr_reader :orientation
22
+ attr_reader :country,
23
+ :id_number,
24
+ :expiry_date,
25
+ :issuance_date,
26
+ :surname,
27
+ :given_names,
28
+ :full_name,
29
+ :birth_date,
30
+ :birth_place,
31
+ :gender,
32
+ :mrz1,
33
+ :mrz2,
34
+ :mrz
35
+
36
+ # @param prediction [Hash]
37
+ # @param input_file [Mindee::InputDocument, nil]
38
+ # @param page_id [Integer, nil]
39
+ def initialize(prediction, input_file: nil, page_id: nil)
40
+ super('passport', input_file: input_file)
41
+ @orientation = Orientation.new(prediction['orientation'], page_id) if page_id
42
+ @country = Field.new(prediction['country'], page_id)
43
+ @id_number = Field.new(prediction['id_number'], page_id)
44
+ @birth_date = DateField.new(prediction['birth_date'], page_id)
45
+ @expiry_date = DateField.new(prediction['expiry_date'], page_id)
46
+ @issuance_date = DateField.new(prediction['issuance_date'], page_id)
47
+ @birth_place = Field.new(prediction['birth_place'], page_id)
48
+ @gender = Field.new(prediction['gender'], page_id)
49
+ @surname = Field.new(prediction['surname'], page_id)
50
+ @mrz1 = Field.new(prediction['mrz1'], page_id)
51
+ @mrz2 = Field.new(prediction['mrz2'], page_id)
52
+ @given_names = []
53
+ prediction['given_names'].each do |item|
54
+ @given_names.push(Field.new(item, page_id))
55
+ end
56
+ @full_name = construct_full_name(page_id)
57
+ @mrz = construct_mrz(page_id)
58
+ check_mrz
59
+ end
60
+
61
+ def to_s
62
+ given_names = @given_names.join(' ')
63
+ out_str = String.new
64
+ out_str << '-----Passport data-----'
65
+ out_str << "\nFilename: #{@filename}".rstrip
66
+ out_str << "\nFull name: #{@full_name}".rstrip
67
+ out_str << "\nGiven names: #{given_names}".rstrip
68
+ out_str << "\nSurname: #{@surname}".rstrip
69
+ out_str << "\nCountry: #{@country}".rstrip
70
+ out_str << "\nID Number: #{@id_number}".rstrip
71
+ out_str << "\nIssuance date: #{@issuance_date}".rstrip
72
+ out_str << "\nBirth date: #{@birth_date}".rstrip
73
+ out_str << "\nExpiry date: #{@expiry_date}".rstrip
74
+ out_str << "\nMRZ 1: #{@mrz1}".rstrip
75
+ out_str << "\nMRZ 2: #{@mrz2}".rstrip
76
+ out_str << "\nMRZ: #{@mrz}".rstrip
77
+ out_str << "\n----------------------"
78
+ out_str
79
+ end
80
+
81
+ # @return [Boolean]
82
+ def expired?
83
+ return true unless @expiry_date.date_object
84
+
85
+ @expiry_date.date_object < Date.today
86
+ end
87
+
88
+ private
89
+
90
+ def check_mrz
91
+ return if @mrz1.value.nil? || @mrz2.value.nil?
92
+
93
+ mrz = MRZ.parse([@mrz1.value, @mrz2.value])
94
+ checks = {
95
+ mrz_valid: valid_mrz?(mrz),
96
+ mrz_valid_birth_date: valid_birth_date?(mrz),
97
+ mrz_valid_expiry_date: valid_expiry_date?(mrz),
98
+ mrz_valid_id_number: valid_id_number?(mrz),
99
+ mrz_valid_surname: valid_surname?(mrz),
100
+ mrz_valid_country: valid_country?(mrz),
101
+ }
102
+ @checklist.merge!(checks)
103
+ end
104
+
105
+ def valid_mrz?(mrz)
106
+ check = mrz.valid?
107
+ @mrz.confidence = 1.0 if check
108
+ check
109
+ end
110
+
111
+ def valid_birth_date?(mrz)
112
+ check = mrz.valid_birth_date? && mrz.birth_date == @birth_date.date_object
113
+ @birth_date.confidence = 1.0 if check
114
+ check
115
+ end
116
+
117
+ def valid_expiry_date?(mrz)
118
+ check = mrz.valid_expiration_date? && mrz.expiration_date == @expiry_date.date_object
119
+ @expiry_date.confidence = 1.0 if check
120
+ check
121
+ end
122
+
123
+ def valid_id_number?(mrz)
124
+ check = mrz.valid_document_number? && mrz.document_number == @id_number.value
125
+ @id_number.confidence = 1.0 if check
126
+ check
127
+ end
128
+
129
+ def valid_surname?(mrz)
130
+ check = mrz.last_name == @surname.value
131
+ @surname.confidence = 1.0 if check
132
+ check
133
+ end
134
+
135
+ def valid_country?(mrz)
136
+ check = mrz.nationality == @country.value
137
+ @country.confidence = 1.0 if check
138
+ check
139
+ end
140
+
141
+ def construct_full_name(page_id)
142
+ return unless @surname.value &&
143
+ !@given_names.empty? &&
144
+ @given_names[0].value
145
+
146
+ full_name = {
147
+ 'value' => "#{@given_names[0].value} #{@surname.value}",
148
+ 'confidence' => Field.array_confidence([@surname, @given_names[0]]),
149
+ }
150
+ Field.new(full_name, page_id, reconstructed: true)
151
+ end
152
+
153
+ def construct_mrz(page_id)
154
+ return if @mrz1.value.nil? || @mrz2.value.nil?
155
+
156
+ mrz = {
157
+ 'value' => @mrz1.value + @mrz2.value,
158
+ 'confidence' => Field.array_confidence([@mrz1, @mrz2]),
159
+ }
160
+ Field.new(mrz, page_id, reconstructed: true)
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../fields'
4
+ require_relative 'base'
5
+
6
+ module Mindee
7
+ # Receipt document.
8
+ class Receipt < Document
9
+ # @return [Mindee::Locale]
10
+ attr_reader :locale
11
+ # @return [Mindee::Amount]
12
+ attr_reader :total_incl
13
+ # @return [Mindee::Amount]
14
+ attr_reader :total_excl
15
+ # @return [Mindee::Amount]
16
+ attr_reader :total_tax
17
+ # @return [Mindee::DateField]
18
+ attr_reader :date
19
+ # @return [Mindee::Field]
20
+ attr_reader :supplier
21
+ # @return [Array<Mindee::TaxField>]
22
+ attr_reader :taxes
23
+ # @return [Mindee::Orientation]
24
+ attr_reader :orientation
25
+ # @return [Mindee::Field]
26
+ attr_reader :time
27
+ # @return [Mindee::Field]
28
+ attr_reader :category
29
+
30
+ # @param prediction [Hash]
31
+ # @param input_file [Mindee::InputDocument, nil]
32
+ # @param page_id [Integer, nil]
33
+ def initialize(prediction, input_file: nil, page_id: nil)
34
+ super('receipt', input_file: input_file)
35
+ @orientation = Orientation.new(prediction['orientation'], page_id) if page_id
36
+ @locale = Locale.new(prediction['locale'])
37
+ @total_incl = Amount.new(prediction['total_incl'], page_id)
38
+ @date = DateField.new(prediction['date'], page_id)
39
+ @category = Field.new(prediction['category'], page_id)
40
+ @supplier = Field.new(prediction['supplier'], page_id)
41
+ @time = Field.new(prediction['time'], page_id)
42
+ @taxes = []
43
+ prediction['taxes'].each do |item|
44
+ @taxes.push(TaxField.new(item, page_id))
45
+ end
46
+
47
+ @total_tax = Amount.new(
48
+ { value: nil, confidence: 0.0 }, page_id
49
+ )
50
+ @total_excl = Amount.new(
51
+ { value: nil, confidence: 0.0 }, page_id
52
+ )
53
+ reconstruct(page_id)
54
+ end
55
+
56
+ def to_s
57
+ taxes = @taxes.join("\n ")
58
+ out_str = String.new
59
+ out_str << '-----Receipt data-----'
60
+ out_str << "\nFilename: #{@filename}".rstrip
61
+ out_str << "\nTotal amount including taxes: #{@total_incl}".rstrip
62
+ out_str << "\nTotal amount excluding taxes: #{@total_excl}".rstrip
63
+ out_str << "\nDate: #{@date}".rstrip
64
+ out_str << "\nCategory: #{@category}".rstrip
65
+ out_str << "\nTime: #{@time}".rstrip
66
+ out_str << "\nMerchant name: #{@supplier}".rstrip
67
+ out_str << "\nTaxes: #{taxes}".rstrip
68
+ out_str << "\nTotal taxes: #{@total_tax}".rstrip
69
+ out_str << "\nLocale: #{@locale}".rstrip
70
+ out_str << "\n----------------------"
71
+ out_str
72
+ end
73
+
74
+ private
75
+
76
+ def reconstruct(page_id)
77
+ construct_total_tax_from_taxes(page_id)
78
+ construct_total_excl(page_id)
79
+ end
80
+
81
+ def construct_total_tax_from_taxes(page_id)
82
+ return if @taxes.empty? || !@total_tax.value.nil?
83
+
84
+ total_tax = {
85
+ 'value' => @taxes.map do |tax|
86
+ if tax.value.nil?
87
+ 0
88
+ else
89
+ tax.value
90
+ end
91
+ end.sum,
92
+ 'confidence' => Field.array_confidence(@taxes),
93
+ }
94
+ return unless total_tax['value'].positive?
95
+
96
+ @total_tax = Amount.new(total_tax, page_id, reconstructed: true)
97
+ end
98
+
99
+ def construct_total_excl(page_id)
100
+ return if @taxes.empty? || @total_incl.value.nil?
101
+
102
+ total_excl = {
103
+ 'value' => @total_incl.value - Field.array_sum(@taxes),
104
+ 'confidence' => Field.array_confidence(@taxes) * @total_incl.confidence,
105
+ }
106
+ @total_excl = Amount.new(total_excl, page_id, reconstructed: true)
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'documents/invoice'
4
+ require_relative 'documents/receipt'
5
+ require_relative 'documents/passport'
6
+ require_relative 'documents/financial_doc'
7
+ require_relative 'documents/custom'
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require_relative 'version'
5
+
6
+ module Mindee
7
+ MINDEE_API_URL = 'https://api.mindee.net/v1'
8
+ USER_AGENT = "mindee-api-ruby@v#{Mindee::VERSION} ruby-v#{RUBY_VERSION} #{Mindee::PLATFORM}"
9
+
10
+ INVOICE_VERSION = '3'
11
+ INVOICE_URL_NAME = 'invoices'
12
+
13
+ RECEIPT_VERSION = '3'
14
+ RECEIPT_URL_NAME = 'expense_receipts'
15
+
16
+ PASSPORT_VERSION = '1'
17
+ PASSPORT_URL_NAME = 'passport'
18
+
19
+ # Generic API endpoint for a product.
20
+ class Endpoint
21
+ attr_reader :api_key
22
+
23
+ def initialize(owner, url_name, version, key_name: nil, api_key: nil)
24
+ @owner = owner
25
+ @url_name = url_name
26
+ @version = version
27
+ @key_name = key_name || url_name
28
+ @api_key = api_key || set_api_key_from_env
29
+ @url_root = "#{MINDEE_API_URL}/products/#{@owner}/#{@url_name}/v#{@version}"
30
+ end
31
+
32
+ # @param input_doc [Mindee::InputDocument]
33
+ # @param include_words [Boolean]
34
+ # @param close_file [Boolean]
35
+ # @return [Net::HTTPResponse]
36
+ def predict_request(input_doc, include_words: false, close_file: true)
37
+ uri = URI("#{@url_root}/predict")
38
+ headers = {
39
+ 'Authorization' => "Token #{@api_key}",
40
+ 'User-Agent' => USER_AGENT,
41
+ }
42
+ req = Net::HTTP::Post.new(uri, headers)
43
+
44
+ params = {
45
+ 'document' => input_doc.read_document(close: close_file),
46
+ }
47
+ params.push ['include_mvision', 'true'] if include_words
48
+
49
+ req.set_form(params, 'multipart/form-data')
50
+
51
+ Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
52
+ http.request(req)
53
+ end
54
+ end
55
+
56
+ def envvar_key_name
57
+ key_name = to_envar(@key_name)
58
+ key_name = "#{to_envar(@owner)}_#{key_name}" if @owner != 'mindee'
59
+ "MINDEE_#{key_name}_API_KEY"
60
+ end
61
+
62
+ private
63
+
64
+ # Create a standard way to get/set environment variable names.
65
+ def to_envar(name)
66
+ name.sub('-', '_').upcase
67
+ end
68
+
69
+ # Set the endpoint's API key from an environment variable, if present.
70
+ # We look first for the specific key, if not set, we'll use the generic key
71
+ def set_api_key_from_env
72
+ env_key = ENV.fetch(envvar_key_name, nil)
73
+ env_key = ENV.fetch('MINDEE_API_KEY', nil) if env_key.nil?
74
+ @api_key = env_key if env_key
75
+ end
76
+ end
77
+
78
+ # Invoice API endpoint
79
+ class InvoiceEndpoint < Endpoint
80
+ def initialize(api_key)
81
+ super('mindee', INVOICE_URL_NAME, INVOICE_VERSION, key_name: 'invoice', api_key: api_key)
82
+ end
83
+ end
84
+
85
+ # Receipt API endpoint
86
+ class ReceiptEndpoint < Endpoint
87
+ def initialize(api_key)
88
+ super('mindee', RECEIPT_URL_NAME, RECEIPT_VERSION, key_name: 'receipt', api_key: api_key)
89
+ end
90
+ end
91
+
92
+ # Passport API endpoint
93
+ class PassportEndpoint < Endpoint
94
+ def initialize(api_key)
95
+ super('mindee', PASSPORT_URL_NAME, PASSPORT_VERSION, api_key: api_key)
96
+ end
97
+ end
98
+
99
+ # Custom (constructed) API endpoint
100
+ class CustomEndpoint < Endpoint
101
+ def initialize(document_type, account_name, version, api_key)
102
+ super(account_name, document_type, version, api_key: api_key)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Mindee
6
+ # Represents tax information.
7
+ class Amount < Field
8
+ # Amount value as 3 decimal float
9
+ # @return [Float, nil]
10
+ attr_reader :value
11
+
12
+ def initialize(prediction, page_id, reconstructed: false)
13
+ super
14
+ @value = @value.round(3) unless @value.nil?
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../geometry'
4
+
5
+ module Mindee
6
+ # Base field object.
7
+ class Field
8
+ # @return [String, Float, Integer, Boolean]
9
+ attr_reader :value
10
+ # @return [Array<Array<Float>>]
11
+ attr_reader :bbox
12
+ # @return [Array<Array<Float>>]
13
+ attr_reader :polygon
14
+ # @return [Integer, nil]
15
+ attr_reader :page_id
16
+ # true if the field was reconstructed or computed using other fields.
17
+ # @return [Boolean]
18
+ attr_reader :reconstructed
19
+ # The confidence score, value will be between 0.0 and 1.0
20
+ # @return [Float]
21
+ attr_accessor :confidence
22
+
23
+ # @param prediction [Hash]
24
+ # @param page_id [Integer, nil]
25
+ # @param reconstructed [Boolean]
26
+ def initialize(prediction, page_id, reconstructed: false)
27
+ @value = prediction['value']
28
+ @confidence = prediction['confidence']
29
+ @polygon = prediction['polygon']
30
+ @bbox = Geometry.get_bbox_as_polygon(@polygon) unless @polygon.nil? || @polygon.empty?
31
+ @page_id = page_id || prediction['page_id']
32
+ @reconstructed = reconstructed
33
+ end
34
+
35
+ def to_s
36
+ @value ? @value.to_s : ''
37
+ end
38
+
39
+ # Multiply all the Mindee::Field confidences in the array.
40
+ def self.array_confidence(field_array)
41
+ product = 1
42
+ field_array.each do |field|
43
+ return 0.0 if field.confidence.nil?
44
+
45
+ product *= field.confidence
46
+ end
47
+ product.to_f
48
+ end
49
+
50
+ # Add all the Mindee::Field values in the array.
51
+ def self.array_sum(field_array)
52
+ arr_sum = 0
53
+ field_array.each do |field|
54
+ return 0.0 if field.value.nil?
55
+
56
+ arr_sum += field.value
57
+ end
58
+ arr_sum.to_f
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mindee
4
+ # Company registration number or code, and its type.
5
+ class CompanyRegistration < Field
6
+ # @return [String]
7
+ attr_reader :type
8
+
9
+ # @param prediction [Hash]
10
+ # @param page_id [Integer, nil]
11
+ # @param reconstructed [Boolean]
12
+ def initialize(prediction, page_id, reconstructed: false)
13
+ super
14
+ @type = prediction['type']
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ require_relative 'base'
6
+
7
+ module Mindee
8
+ # Represents a date.
9
+ class DateField < Field
10
+ # The date as a standard Ruby `Date` object.
11
+ # @return [Date, nil]
12
+ attr_reader :date_object
13
+ # The ISO 8601 representation of the date, regardless of the `raw` contents.
14
+ # @return [String, nil]
15
+ attr_reader :value
16
+ # The textual representation of the date as found on the document.
17
+ # @return [String, nil]
18
+ attr_reader :raw
19
+
20
+ # @param prediction [Hash]
21
+ # @param page_id [Integer, nil]
22
+ def initialize(prediction, page_id)
23
+ super
24
+ return unless @value
25
+
26
+ @date_object = Date.parse(@value)
27
+ @raw = prediction['raw']
28
+ end
29
+ end
30
+ end