mindee 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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