mindee 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) 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 +21 -0
  6. data/README.md +46 -23
  7. data/Rakefile +6 -1
  8. data/bin/mindee.rb +70 -61
  9. data/docs/ruby-api-builder.md +131 -0
  10. data/docs/ruby-getting-started.md +265 -0
  11. data/docs/ruby-invoice-ocr.md +261 -0
  12. data/docs/ruby-passport-ocr.md +156 -0
  13. data/docs/ruby-receipt-ocr.md +170 -0
  14. data/lib/mindee/client.rb +128 -93
  15. data/lib/mindee/document_config.rb +22 -154
  16. data/lib/mindee/geometry.rb +105 -8
  17. data/lib/mindee/http/endpoint.rb +80 -0
  18. data/lib/mindee/input/pdf_processing.rb +106 -0
  19. data/lib/mindee/input/sources.rb +97 -0
  20. data/lib/mindee/input.rb +3 -0
  21. data/lib/mindee/parsing/document.rb +31 -0
  22. data/lib/mindee/parsing/error.rb +22 -0
  23. data/lib/mindee/parsing/inference.rb +53 -0
  24. data/lib/mindee/parsing/page.rb +46 -0
  25. data/lib/mindee/parsing/prediction/base.rb +30 -0
  26. data/lib/mindee/{fields → parsing/prediction/common_fields}/amount.rb +5 -1
  27. data/lib/mindee/{fields → parsing/prediction/common_fields}/base.rb +16 -5
  28. data/lib/mindee/{fields → parsing/prediction/common_fields}/company_registration.rb +0 -0
  29. data/lib/mindee/{fields/datefield.rb → parsing/prediction/common_fields/date.rb} +0 -0
  30. data/lib/mindee/{fields → parsing/prediction/common_fields}/locale.rb +0 -0
  31. data/lib/mindee/{fields → parsing/prediction/common_fields}/payment_details.rb +0 -0
  32. data/lib/mindee/parsing/prediction/common_fields/position.rb +39 -0
  33. data/lib/mindee/{fields → parsing/prediction/common_fields}/tax.rb +7 -2
  34. data/lib/mindee/parsing/prediction/common_fields/text.rb +12 -0
  35. data/lib/mindee/parsing/prediction/common_fields.rb +11 -0
  36. data/lib/mindee/parsing/prediction/custom/custom_v1.rb +58 -0
  37. data/lib/mindee/{fields/custom_docs.rb → parsing/prediction/custom/fields.rb} +5 -5
  38. data/lib/mindee/parsing/prediction/eu/license_plate/license_plate_v1.rb +34 -0
  39. data/lib/mindee/parsing/prediction/fr/bank_account_details/bank_account_details_v1.rb +40 -0
  40. data/lib/mindee/parsing/prediction/fr/carte_vitale/carte_vitale_v1.rb +49 -0
  41. data/lib/mindee/parsing/prediction/fr/id_card/id_card_v1.rb +84 -0
  42. data/lib/mindee/parsing/prediction/invoice/invoice_line_item.rb +58 -0
  43. data/lib/mindee/parsing/prediction/invoice/invoice_v4.rb +216 -0
  44. data/lib/mindee/parsing/prediction/passport/passport_v1.rb +184 -0
  45. data/lib/mindee/parsing/prediction/receipt/receipt_v4.rb +84 -0
  46. data/lib/mindee/parsing/prediction/shipping_container/shipping_container_v1.rb +38 -0
  47. data/lib/mindee/parsing/prediction/us/bank_check/bank_check_v1.rb +70 -0
  48. data/lib/mindee/parsing/prediction.rb +12 -0
  49. data/lib/mindee/parsing.rb +4 -0
  50. data/lib/mindee/version.rb +1 -1
  51. data/mindee.gemspec +2 -1
  52. metadata +57 -24
  53. data/lib/mindee/documents/base.rb +0 -35
  54. data/lib/mindee/documents/custom.rb +0 -65
  55. data/lib/mindee/documents/financial_doc.rb +0 -135
  56. data/lib/mindee/documents/invoice.rb +0 -162
  57. data/lib/mindee/documents/passport.rb +0 -163
  58. data/lib/mindee/documents/receipt.rb +0 -109
  59. data/lib/mindee/documents.rb +0 -7
  60. data/lib/mindee/endpoint.rb +0 -105
  61. data/lib/mindee/fields/orientation.rb +0 -26
  62. data/lib/mindee/fields.rb +0 -11
  63. data/lib/mindee/inputs.rb +0 -153
  64. 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