mindee 1.1.2 → 2.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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.rubocop.yml +2 -2
  4. data/.yardopts +4 -0
  5. data/CHANGELOG.md +25 -0
  6. data/Gemfile +0 -7
  7. data/README.md +52 -21
  8. data/Rakefile +6 -1
  9. data/bin/mindee.rb +70 -61
  10. data/docs/ruby-api-builder.md +131 -0
  11. data/docs/ruby-getting-started.md +265 -0
  12. data/docs/ruby-invoice-ocr.md +261 -0
  13. data/docs/ruby-passport-ocr.md +156 -0
  14. data/docs/ruby-receipt-ocr.md +170 -0
  15. data/lib/mindee/client.rb +128 -93
  16. data/lib/mindee/document_config.rb +22 -154
  17. data/lib/mindee/geometry.rb +105 -8
  18. data/lib/mindee/http/endpoint.rb +80 -0
  19. data/lib/mindee/input/pdf_processing.rb +106 -0
  20. data/lib/mindee/input/sources.rb +97 -0
  21. data/lib/mindee/input.rb +3 -0
  22. data/lib/mindee/parsing/document.rb +31 -0
  23. data/lib/mindee/parsing/error.rb +22 -0
  24. data/lib/mindee/parsing/inference.rb +53 -0
  25. data/lib/mindee/parsing/page.rb +46 -0
  26. data/lib/mindee/parsing/prediction/base.rb +30 -0
  27. data/lib/mindee/{fields → parsing/prediction/common_fields}/amount.rb +5 -1
  28. data/lib/mindee/{fields → parsing/prediction/common_fields}/base.rb +16 -5
  29. data/lib/mindee/{fields → parsing/prediction/common_fields}/company_registration.rb +0 -0
  30. data/lib/mindee/{fields/datefield.rb → parsing/prediction/common_fields/date.rb} +0 -0
  31. data/lib/mindee/{fields → parsing/prediction/common_fields}/locale.rb +0 -0
  32. data/lib/mindee/{fields → parsing/prediction/common_fields}/payment_details.rb +0 -0
  33. data/lib/mindee/parsing/prediction/common_fields/position.rb +39 -0
  34. data/lib/mindee/{fields → parsing/prediction/common_fields}/tax.rb +7 -2
  35. data/lib/mindee/parsing/prediction/common_fields/text.rb +12 -0
  36. data/lib/mindee/parsing/prediction/common_fields.rb +11 -0
  37. data/lib/mindee/parsing/prediction/custom/custom_v1.rb +58 -0
  38. data/lib/mindee/{fields/custom_docs.rb → parsing/prediction/custom/fields.rb} +5 -5
  39. data/lib/mindee/parsing/prediction/eu/license_plate/license_plate_v1.rb +34 -0
  40. data/lib/mindee/parsing/prediction/fr/bank_account_details/bank_account_details_v1.rb +40 -0
  41. data/lib/mindee/parsing/prediction/fr/carte_vitale/carte_vitale_v1.rb +49 -0
  42. data/lib/mindee/parsing/prediction/fr/id_card/id_card_v1.rb +84 -0
  43. data/lib/mindee/parsing/prediction/invoice/invoice_line_item.rb +58 -0
  44. data/lib/mindee/parsing/prediction/invoice/invoice_v4.rb +216 -0
  45. data/lib/mindee/parsing/prediction/passport/passport_v1.rb +184 -0
  46. data/lib/mindee/parsing/prediction/receipt/receipt_v4.rb +84 -0
  47. data/lib/mindee/parsing/prediction/shipping_container/shipping_container_v1.rb +38 -0
  48. data/lib/mindee/parsing/prediction/us/bank_check/bank_check_v1.rb +70 -0
  49. data/lib/mindee/parsing/prediction.rb +12 -0
  50. data/lib/mindee/parsing.rb +4 -0
  51. data/lib/mindee/version.rb +1 -1
  52. data/mindee.gemspec +11 -5
  53. metadata +105 -30
  54. data/lib/mindee/documents/base.rb +0 -35
  55. data/lib/mindee/documents/custom.rb +0 -65
  56. data/lib/mindee/documents/financial_doc.rb +0 -135
  57. data/lib/mindee/documents/invoice.rb +0 -162
  58. data/lib/mindee/documents/passport.rb +0 -163
  59. data/lib/mindee/documents/receipt.rb +0 -109
  60. data/lib/mindee/documents.rb +0 -7
  61. data/lib/mindee/endpoint.rb +0 -105
  62. data/lib/mindee/fields/orientation.rb +0 -26
  63. data/lib/mindee/fields.rb +0 -11
  64. data/lib/mindee/inputs.rb +0 -153
  65. data/lib/mindee/response.rb +0 -27
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mindee
4
+ # An element's position on the image
5
+ class PositionField
6
+ # @return [Mindee::Geometry::Polygon]
7
+ attr_reader :polygon
8
+ # @return [Mindee::Geometry::Polygon]
9
+ attr_reader :value
10
+ # @return [Mindee::Geometry::Quadrilateral]
11
+ attr_reader :quadrangle
12
+ # @return [Mindee::Geometry::Quadrilateral]
13
+ attr_reader :rectangle
14
+ # @return [Mindee::Geometry::Quadrilateral]
15
+ attr_reader :bounding_box
16
+
17
+ # @param prediction [Hash]
18
+ # @param page_id [Integer, nil]
19
+ def initialize(prediction, page_id)
20
+ @polygon = Geometry.polygon_from_prediction(prediction['polygon']) unless prediction['polygon'].empty?
21
+ @quadrangle = to_quadrilateral(prediction, 'quadrangle')
22
+ @rectangle = to_quadrilateral(prediction, 'rectangle')
23
+ @bounding_box = to_quadrilateral(prediction, 'bounding_box')
24
+ @page_id = page_id || prediction['page_id']
25
+ @value = @polygon
26
+ end
27
+
28
+ def to_s
29
+ out_str = String.new
30
+ out_str << "Polygon with #{@polygon.size} points."
31
+ end
32
+
33
+ private
34
+
35
+ def to_quadrilateral(prediction, key)
36
+ Geometry.quadrilateral_from_prediction(prediction[key]) unless prediction[key].empty?
37
+ end
38
+ end
39
+ end
@@ -24,10 +24,15 @@ module Mindee
24
24
  @code = prediction['code'] unless prediction['code'] == 'None'
25
25
  end
26
26
 
27
+ # @param value [Float]
28
+ def print_float(value)
29
+ format('%.2f', value)
30
+ end
31
+
27
32
  def to_s
28
33
  out_str = String.new
29
- out_str << "#{@value} " if @value
30
- out_str << "#{@rate}% " if @rate
34
+ out_str << "#{print_float(@value)} " if @value
35
+ out_str << "#{print_float(@rate)}% " if @rate
31
36
  out_str << "#{@code} " if @code
32
37
  out_str.strip
33
38
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Mindee
6
+ # Represents tax information.
7
+ class TextField < Field
8
+ # Amount value as 3 decimal float
9
+ # @return [String, nil]
10
+ attr_reader :value
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'common_fields/amount'
4
+ require_relative 'common_fields/base'
5
+ require_relative 'common_fields/company_registration'
6
+ require_relative 'common_fields/date'
7
+ require_relative 'common_fields/locale'
8
+ require_relative 'common_fields/payment_details'
9
+ require_relative 'common_fields/position'
10
+ require_relative 'common_fields/tax'
11
+ require_relative 'common_fields/text'
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'fields'
4
+ require_relative '../base'
5
+
6
+ module Mindee
7
+ module Prediction
8
+ # Custom document object.
9
+ class CustomV1 < Prediction
10
+ # All value fields in the document
11
+ # @return [Hash<Symbol, Mindee::ListField>]
12
+ attr_reader :fields
13
+ # All classifications in the document
14
+ # @return [Hash<Symbol, Mindee::ClassificationField>]
15
+ attr_reader :classifications
16
+
17
+ # @param prediction [Hash]
18
+ # @param page_id [Integer, nil]
19
+ def initialize(prediction, page_id)
20
+ super
21
+ @fields = {}
22
+ @classifications = {}
23
+ prediction.each do |field_name, field_prediction|
24
+ field_sym = field_name.to_sym
25
+ set_field(field_sym, field_prediction, page_id)
26
+ end
27
+ end
28
+
29
+ def to_s
30
+ out_str = String.new
31
+ @classifications.each do |name, info|
32
+ out_str << "\n:#{name}: #{info}".rstrip
33
+ end
34
+ @fields.each do |name, info|
35
+ out_str << "\n:#{name}: #{info}".rstrip
36
+ end
37
+ out_str[1..].to_s
38
+ end
39
+
40
+ private
41
+
42
+ # @param field_prediction [Hash]
43
+ def set_field(field_sym, field_prediction, page_id)
44
+ # Currently two types of fields possible in a custom API response:
45
+ # fields having a list of values, and classification fields.
46
+ # Here we use the fact that only value lists have the 'values' attribute.
47
+
48
+ if field_prediction.key? 'values'
49
+ @fields[field_sym] = ListField.new(field_prediction, page_id)
50
+ elsif field_prediction.key? 'value'
51
+ @classifications[field_sym] = ClassificationField.new(field_prediction)
52
+ else
53
+ throw 'Unknown API field type'
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -26,9 +26,9 @@ module Mindee
26
26
  # The confidence score, value will be between 0.0 and 1.0
27
27
  # @return [Float]
28
28
  attr_accessor :confidence
29
- # @return [Array<Array<Float>>]
30
- attr_reader :bbox
31
- # @return [Array<Array<Float>>]
29
+ # @return [Mindee::Geometry::Quadrilateral]
30
+ attr_reader :bounding_box
31
+ # @return [Mindee::Geometry::Polygon]
32
32
  attr_reader :polygon
33
33
  attr_reader :content
34
34
 
@@ -36,8 +36,8 @@ module Mindee
36
36
  def initialize(prediction)
37
37
  @content = prediction['content']
38
38
  @confidence = prediction['confidence']
39
- @polygon = prediction['polygon']
40
- @bbox = Geometry.get_bbox_as_polygon(@polygon) unless @polygon.nil? || @polygon.empty?
39
+ @polygon = Geometry.polygon_from_prediction(prediction['polygon'])
40
+ @bounding_box = Geometry.get_bounding_box(@polygon) unless @polygon.nil? || @polygon.empty?
41
41
  end
42
42
 
43
43
  # @return [String]
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../common_fields'
4
+ require_relative '../../base'
5
+
6
+ module Mindee
7
+ module Prediction
8
+ module EU
9
+ # License plate prediction.
10
+ class LicensePlateV1 < Prediction
11
+ # A list of license plates.
12
+ # @return [Array<Mindee::TextField>]
13
+ attr_reader :license_plates
14
+
15
+ # @param prediction [Hash]
16
+ # @param page_id [Integer, nil]
17
+ def initialize(prediction, page_id)
18
+ super
19
+ @license_plates = []
20
+ prediction['license_plates'].each do |item|
21
+ @license_plates.push(TextField.new(item, page_id))
22
+ end
23
+ end
24
+
25
+ def to_s
26
+ license_plates = @license_plates.map(&:value).join(', ')
27
+ out_str = String.new
28
+ out_str << "\n:License plates: #{license_plates}".rstrip
29
+ out_str[1..].to_s
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../common_fields'
4
+ require_relative '../../base'
5
+
6
+ module Mindee
7
+ module Prediction
8
+ module FR
9
+ # French bank account information (RIB)
10
+ class BankAccountDetailsV1 < Prediction
11
+ # The account's IBAN.
12
+ # @return [Mindee::TextField]
13
+ attr_reader :iban
14
+ # The account holder's name.
15
+ # @return [Mindee::TextField]
16
+ attr_reader :account_holder_name
17
+ # The bank's SWIFT code.
18
+ # @return [Mindee::TextField]
19
+ attr_reader :swift
20
+
21
+ # @param prediction [Hash]
22
+ # @param page_id [Integer, nil]
23
+ def initialize(prediction, page_id)
24
+ super
25
+ @iban = TextField.new(prediction['iban'], page_id)
26
+ @account_holder_name = TextField.new(prediction['account_holder_name'], page_id)
27
+ @swift = TextField.new(prediction['swift'], page_id)
28
+ end
29
+
30
+ def to_s
31
+ out_str = String.new
32
+ out_str << "\n:IBAN: #{@iban}".rstrip
33
+ out_str << "\n:Account holder name: #{@account_holder_name}".rstrip
34
+ out_str << "\n:SWIFT: #{@swift}".rstrip
35
+ out_str[1..].to_s
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../common_fields'
4
+ require_relative '../../base'
5
+
6
+ module Mindee
7
+ module Prediction
8
+ module FR
9
+ # French Carte Vitale
10
+ class CarteVitaleV1 < Prediction
11
+ # List of given (first) names of the cardholder.
12
+ # @return [Array<Mindee::TextField>]
13
+ attr_reader :given_names
14
+ # The surname (last name) of the cardholder.
15
+ # @return [Mindee::TextField]
16
+ attr_reader :surname
17
+ # The social security number of the cardholder.
18
+ # @return [Mindee::TextField]
19
+ attr_reader :social_security
20
+ # The issuance date of the card.
21
+ # @return [Mindee::DateField]
22
+ attr_reader :issuance_date
23
+
24
+ # @param prediction [Hash]
25
+ # @param page_id [Integer, nil]
26
+ def initialize(prediction, page_id)
27
+ super
28
+ @given_names = []
29
+ prediction['given_names'].each do |item|
30
+ @given_names.push(TextField.new(item, page_id))
31
+ end
32
+ @surname = TextField.new(prediction['surname'], page_id)
33
+ @social_security = TextField.new(prediction['social_security'], page_id)
34
+ @issuance_date = DateField.new(prediction['issuance_date'], page_id)
35
+ end
36
+
37
+ def to_s
38
+ given_names = @given_names.map(&:value).join(', ')
39
+ out_str = String.new
40
+ out_str << "\n:Given names: #{given_names}".rstrip
41
+ out_str << "\n:Surname: #{@surname}".rstrip
42
+ out_str << "\n:Social Security Number: #{@social_security}".rstrip
43
+ out_str << "\n:Issuance date: #{@issuance_date}".rstrip
44
+ out_str[1..].to_s
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../common_fields'
4
+ require_relative '../../base'
5
+
6
+ module Mindee
7
+ module Prediction
8
+ module FR
9
+ # French national ID card
10
+ class IdCardV1 < Prediction
11
+ # The authority which has issued the card.
12
+ # @return [Array<Mindee::TextField>]
13
+ attr_reader :authority
14
+ # Indicates if it is the recto side, the verso side or both.
15
+ # @return [Mindee::TextField]
16
+ attr_reader :document_side
17
+ # The card number.
18
+ # @return [Mindee::TextField]
19
+ attr_reader :id_number
20
+ # The expiration date of the card.
21
+ # @return [Mindee::DateField]
22
+ attr_reader :expiry_date
23
+ # The surname (last name) of the cardholder.
24
+ # @return [Mindee::TextField]
25
+ attr_reader :surname
26
+ # List of first (given) names of the cardholder.
27
+ # @return [Mindee::TextField]
28
+ attr_reader :given_names
29
+ # The date of birth of the cardholder.
30
+ # @return [Mindee::DateField]
31
+ attr_reader :birth_date
32
+ # The place of birth of the cardholder.
33
+ # @return [Mindee::TextField]
34
+ attr_reader :birth_place
35
+ # The sex or gender of the cardholder.
36
+ # @return [Mindee::TextField]
37
+ attr_reader :gender
38
+ # The value of the first MRZ line.
39
+ # @return [Mindee::TextField]
40
+ attr_reader :mrz1
41
+ # The value of the second MRZ line.
42
+ # @return [Mindee::TextField]
43
+ attr_reader :mrz2
44
+
45
+ # @param prediction [Hash]
46
+ # @param page_id [Integer, nil]
47
+ def initialize(prediction, page_id)
48
+ super
49
+ @document_side = TextField.new(prediction['document_side'], page_id) if page_id
50
+ @authority = TextField.new(prediction['authority'], page_id)
51
+ @id_number = TextField.new(prediction['id_number'], page_id)
52
+ @birth_date = DateField.new(prediction['birth_date'], page_id)
53
+ @expiry_date = DateField.new(prediction['expiry_date'], page_id)
54
+ @birth_place = TextField.new(prediction['birth_place'], page_id)
55
+ @gender = TextField.new(prediction['gender'], page_id)
56
+ @surname = TextField.new(prediction['surname'], page_id)
57
+ @mrz1 = TextField.new(prediction['mrz1'], page_id)
58
+ @mrz2 = TextField.new(prediction['mrz2'], page_id)
59
+ @given_names = []
60
+ prediction['given_names'].each do |item|
61
+ @given_names.push(TextField.new(item, page_id))
62
+ end
63
+ end
64
+
65
+ def to_s
66
+ given_names = @given_names.map(&:value).join(', ')
67
+ out_str = String.new
68
+ out_str << "\n:Document side: #{@document_side}".rstrip if @document_side
69
+ out_str << "\n:Authority: #{@authority}".rstrip
70
+ out_str << "\n:Given names: #{given_names}".rstrip
71
+ out_str << "\n:Surname: #{@surname}".rstrip
72
+ out_str << "\n:Gender: #{@gender}".rstrip
73
+ out_str << "\n:ID Number: #{@id_number}".rstrip
74
+ out_str << "\n:Birth date: #{@birth_date}".rstrip
75
+ out_str << "\n:Birth place: #{@birth_place}".rstrip
76
+ out_str << "\n:Expiry date: #{@expiry_date}".rstrip
77
+ out_str << "\n:MRZ 1: #{@mrz1}".rstrip
78
+ out_str << "\n:MRZ 2: #{@mrz2}".rstrip
79
+ out_str[1..].to_s
80
+ end
81
+ end
82
+ end
83
+ end
84
+ 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
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../common_fields'
4
+ require_relative 'invoice_line_item'
5
+ require_relative '../base'
6
+
7
+ module Mindee
8
+ module Prediction
9
+ # Invoice document.
10
+ class InvoiceV4 < Prediction
11
+ # Locale information.
12
+ # @return [Mindee::Locale]
13
+ attr_reader :locale
14
+ # The nature of the invoice.
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 invoice.
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 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
+
66
+ # @param prediction [Hash]
67
+ # @param page_id [Integer, nil]
68
+ def initialize(prediction, page_id)
69
+ super
70
+ @locale = Locale.new(prediction['locale'])
71
+ @document_type = TextField.new(prediction['document_type'], page_id)
72
+ @total_amount = AmountField.new(prediction['total_amount'], page_id)
73
+ @total_net = AmountField.new(prediction['total_net'], page_id)
74
+ @customer_address = TextField.new(prediction['customer_address'], page_id)
75
+ @customer_name = TextField.new(prediction['customer_name'], page_id)
76
+ @date = DateField.new(prediction['date'], page_id)
77
+ @due_date = DateField.new(prediction['due_date'], page_id)
78
+ @invoice_number = TextField.new(prediction['invoice_number'], page_id)
79
+ @supplier_name = TextField.new(prediction['supplier_name'], page_id)
80
+ @supplier_address = TextField.new(prediction['supplier_address'], page_id)
81
+
82
+ @reference_numbers = []
83
+ prediction['reference_numbers'].each do |item|
84
+ @reference_numbers.push(TextField.new(item, page_id))
85
+ end
86
+ @customer_company_registrations = []
87
+ prediction['customer_company_registrations'].each do |item|
88
+ @customer_company_registrations.push(CompanyRegistration.new(item, page_id))
89
+ end
90
+ @taxes = []
91
+ prediction['taxes'].each do |item|
92
+ @taxes.push(TaxField.new(item, page_id))
93
+ end
94
+ @supplier_payment_details = []
95
+ prediction['supplier_payment_details'].each do |item|
96
+ @supplier_payment_details.push(PaymentDetails.new(item, page_id))
97
+ end
98
+ @supplier_company_registrations = []
99
+ prediction['supplier_company_registrations'].each do |item|
100
+ @supplier_company_registrations.push(CompanyRegistration.new(item, page_id))
101
+ end
102
+
103
+ @total_tax = AmountField.new(
104
+ { value: nil, confidence: 0.0 }, page_id
105
+ )
106
+
107
+ @line_items = []
108
+ prediction['line_items'].each do |item|
109
+ @line_items.push(InvoiceLineItem.new(item, page_id))
110
+ end
111
+ reconstruct(page_id)
112
+ end
113
+
114
+ def to_s
115
+ customer_company_registrations = @customer_company_registrations.map(&:value).join('; ')
116
+ supplier_payment_details = @supplier_payment_details.map(&:to_s).join("\n ")
117
+ supplier_company_registrations = @supplier_company_registrations.map(&:to_s).join('; ')
118
+ reference_numbers = @reference_numbers.map(&:to_s).join(', ')
119
+ taxes = @taxes.join("\n ")
120
+ out_str = String.new
121
+ out_str << "\n:Locale: #{@locale}".rstrip
122
+ out_str << "\n:Document type: #{@document_type}".rstrip
123
+ out_str << "\n:Invoice number: #{@invoice_number}".rstrip
124
+ out_str << "\n:Reference numbers: #{reference_numbers}".rstrip
125
+ out_str << "\n:Invoice date: #{@date}".rstrip
126
+ out_str << "\n:Invoice due date: #{@due_date}".rstrip
127
+
128
+ out_str << "\n:Supplier name: #{@supplier_name}".rstrip
129
+ out_str << "\n:Supplier address: #{@supplier_address}".rstrip
130
+ out_str << "\n:Supplier company registrations: #{supplier_company_registrations}".rstrip
131
+ out_str << "\n:Supplier payment details: #{supplier_payment_details}".rstrip
132
+
133
+ out_str << "\n:Customer name: #{@customer_name}".rstrip
134
+ out_str << "\n:Customer address: #{@customer_address}".rstrip
135
+ out_str << "\n:Customer company registrations: #{customer_company_registrations}".rstrip
136
+
137
+ out_str << "\n:Taxes: #{taxes}".rstrip
138
+ out_str << "\n:Total net: #{@total_net}".rstrip
139
+ out_str << "\n:Total taxes: #{@total_tax}".rstrip
140
+ out_str << "\n:Total amount: #{@total_amount}".rstrip
141
+ out_str << line_items_to_s
142
+
143
+ out_str[1..].to_s
144
+ end
145
+
146
+ private
147
+
148
+ def line_items_to_s
149
+ return '' if @line_items.empty?
150
+
151
+ line_item_separator = "#{'=' * 22} #{'=' * 8} #{'=' * 9} #{'=' * 10} #{'=' * 18} #{'=' * 36}"
152
+ line_items = @line_items.map(&:to_s).join("\n")
153
+ out_str = String.new
154
+ out_str << "\n\n:Line Items:"
155
+ out_str << "\n#{line_item_separator}"
156
+ out_str << "\nCode QTY Price Amount Tax (Rate) Description"
157
+ out_str << "\n#{line_item_separator}"
158
+ out_str << "\n#{line_items}"
159
+ out_str << "\n#{line_item_separator}" unless line_items.empty?
160
+ end
161
+
162
+ def reconstruct(page_id)
163
+ construct_total_tax_from_taxes(page_id)
164
+ return unless page_id.nil?
165
+
166
+ construct_total_excl_from_tcc_and_taxes(page_id)
167
+ construct_total_incl_from_taxes_plus_excl(page_id)
168
+ construct_total_tax_from_totals(page_id)
169
+ end
170
+
171
+ def construct_total_excl_from_tcc_and_taxes(page_id)
172
+ return if @total_amount.value.nil? || taxes.empty? || !@total_net.value.nil?
173
+
174
+ total_excl = {
175
+ 'value' => @total_amount.value - @taxes.map(&:value).sum,
176
+ 'confidence' => TextField.array_confidence(@taxes) * @total_amount.confidence,
177
+ }
178
+ @total_net = AmountField.new(total_excl, page_id, reconstructed: true)
179
+ end
180
+
181
+ def construct_total_incl_from_taxes_plus_excl(page_id)
182
+ return if @total_net.value.nil? || @taxes.empty? || !@total_amount.value.nil?
183
+
184
+ total_incl = {
185
+ 'value' => @taxes.map(&:value).sum + @total_net.value,
186
+ 'confidence' => TextField.array_confidence(@taxes) * @total_net.confidence,
187
+ }
188
+ @total_amount = AmountField.new(total_incl, page_id, reconstructed: true)
189
+ end
190
+
191
+ def construct_total_tax_from_taxes(page_id)
192
+ return if @taxes.empty?
193
+
194
+ total_tax = {
195
+ 'value' => @taxes.map(&:value).sum,
196
+ 'confidence' => TextField.array_confidence(@taxes),
197
+ }
198
+ return unless total_tax['value'].positive?
199
+
200
+ @total_tax = AmountField.new(total_tax, page_id, reconstructed: true)
201
+ end
202
+
203
+ def construct_total_tax_from_totals(page_id)
204
+ return if !@total_tax.value.nil? || @total_amount.value.nil? || @total_net.value.nil?
205
+
206
+ total_tax = {
207
+ 'value' => @total_amount.value - @total_net.value,
208
+ 'confidence' => TextField.array_confidence(@taxes),
209
+ }
210
+ return unless total_tax['value'] >= 0
211
+
212
+ @total_tax = AmountField.new(total_tax, page_id, reconstructed: true)
213
+ end
214
+ end
215
+ end
216
+ end