atlas_engine 1.0.0 → 1.2.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +39 -24
  3. data/app/countries/atlas_engine/at/country_profile.yml +1 -1
  4. data/app/countries/atlas_engine/au/country_profile.yml +1 -1
  5. data/app/countries/atlas_engine/be/country_profile.yml +2 -2
  6. data/app/countries/atlas_engine/ch/country_profile.yml +1 -1
  7. data/app/countries/atlas_engine/fr/country_profile.yml +1 -1
  8. data/app/countries/atlas_engine/nl/country_profile.yml +1 -1
  9. data/app/countries/atlas_engine/pl/country_profile.yml +1 -1
  10. data/app/countries/atlas_engine/us/country_profile.yml +1 -0
  11. data/app/graphql/atlas_engine/schema.graphql +14 -1
  12. data/app/graphql/atlas_engine/types/address_validation/address_input.rb +4 -0
  13. data/app/graphql/atlas_engine/types/address_validation/concern_type.rb +8 -1
  14. data/app/graphql/atlas_engine/types/address_validation/suggestion_type.rb +4 -0
  15. data/app/graphql/atlas_engine/types/message_format_type.rb +11 -0
  16. data/app/graphql/atlas_engine/types/query_type.rb +3 -1
  17. data/app/lib/atlas_engine/validation_transcriber/address_parsings.rb +14 -9
  18. data/app/lib/atlas_engine/validation_transcriber/formatter.rb +10 -1
  19. data/app/models/atlas_engine/address_number_range.rb +1 -1
  20. data/app/models/atlas_engine/address_validation/abstract_address.rb +12 -0
  21. data/app/models/atlas_engine/address_validation/address.rb +8 -0
  22. data/app/models/atlas_engine/address_validation/concern_record.rb +28 -0
  23. data/app/models/atlas_engine/address_validation/es/validators/full_address.rb +18 -5
  24. data/app/models/atlas_engine/address_validation/es/validators/full_address_street.rb +2 -2
  25. data/app/models/atlas_engine/address_validation/full_address_validator_base.rb +6 -2
  26. data/app/models/atlas_engine/address_validation/message_format.rb +13 -0
  27. data/app/models/atlas_engine/address_validation/predicate_pipeline_builder.rb +90 -0
  28. data/app/models/atlas_engine/address_validation/request.rb +1 -0
  29. data/app/models/atlas_engine/address_validation/suggestion.rb +26 -1
  30. data/app/models/atlas_engine/address_validation/validator.rb +31 -14
  31. data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result.rb +9 -5
  32. data/app/models/atlas_engine/address_validation/validators/full_address/candidate_result_base.rb +4 -3
  33. data/app/models/atlas_engine/address_validation/validators/full_address/concern_builder.rb +19 -4
  34. data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_concern_builder.rb +4 -3
  35. data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_country_concern_builder.rb +6 -4
  36. data/app/models/atlas_engine/address_validation/validators/full_address/invalid_zip_for_province_concern_builder.rb +4 -2
  37. data/app/models/atlas_engine/address_validation/validators/full_address/no_candidate_result.rb +1 -1
  38. data/app/models/atlas_engine/address_validation/validators/full_address/suggestion_builder.rb +9 -2
  39. data/app/models/atlas_engine/address_validation/validators/full_address/unknown_address_concern_builder.rb +16 -4
  40. data/app/models/atlas_engine/address_validation/validators/full_address/unknown_province_concern_builder.rb +8 -3
  41. data/app/models/atlas_engine/address_validation/validators/full_address/unmatched_field_concern_builder.rb +13 -3
  42. data/app/models/atlas_engine/address_validation/validators/full_address/unsupported_script_result.rb +1 -1
  43. data/app/models/atlas_engine/address_validation/validators/predicates/city/present.rb +1 -1
  44. data/app/models/atlas_engine/address_validation/validators/predicates/country/exists.rb +5 -1
  45. data/app/models/atlas_engine/address_validation/validators/predicates/country/valid_for_zip.rb +1 -1
  46. data/app/models/atlas_engine/address_validation/validators/predicates/neighborhood/present.rb +35 -0
  47. data/app/models/atlas_engine/address_validation/validators/predicates/not_exceed_max_length.rb +18 -3
  48. data/app/models/atlas_engine/address_validation/validators/predicates/phone/valid.rb +3 -1
  49. data/app/models/atlas_engine/address_validation/validators/predicates/predicate.rb +6 -2
  50. data/app/models/atlas_engine/address_validation/validators/predicates/province/exists.rb +3 -1
  51. data/app/models/atlas_engine/address_validation/validators/predicates/province/valid_for_country.rb +3 -1
  52. data/app/models/atlas_engine/address_validation/validators/predicates/street/present.rb +3 -1
  53. data/app/models/atlas_engine/address_validation/validators/predicates/street_name/present.rb +35 -0
  54. data/app/models/atlas_engine/address_validation/validators/predicates/street_number/present.rb +35 -0
  55. data/app/models/atlas_engine/address_validation/validators/predicates/zip/present.rb +2 -2
  56. data/app/models/atlas_engine/address_validation/validators/predicates/zip/valid_for_country.rb +1 -1
  57. data/app/models/atlas_engine/address_validation/validators/predicates/zip/valid_for_province.rb +1 -1
  58. data/app/models/atlas_engine/services/validation.rb +4 -0
  59. data/db/data/validation_pipelines/es.yml +46 -0
  60. data/db/data/validation_pipelines/es_street.yml +46 -0
  61. data/db/data/validation_pipelines/local.yml +46 -0
  62. data/lib/atlas_engine/version.rb +1 -1
  63. metadata +39 -5
@@ -0,0 +1,90 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module AtlasEngine
5
+ module AddressValidation
6
+ class PredicatePipelineBuilder
7
+ extend T::Sig
8
+
9
+ sig { returns(PredicatePipeline) }
10
+ attr_reader :predicate_pipeline
11
+
12
+ sig { returns(AbstractAddress) }
13
+ attr_reader :address
14
+
15
+ sig { returns(Result) }
16
+ attr_reader :result
17
+
18
+ sig { returns(MessageFormat) }
19
+ attr_reader :message_format
20
+
21
+ sig do
22
+ params(
23
+ matching_strategy_name: String,
24
+ address: AbstractAddress,
25
+ result: Result,
26
+ message_format: MessageFormat,
27
+ ).void
28
+ end
29
+ def initialize(matching_strategy_name:, address:, result:, message_format:)
30
+ @address = address
31
+ @predicate_pipeline = T.let(PredicatePipeline.find(matching_strategy_name), PredicatePipeline)
32
+ @result = result
33
+ @message_format = message_format
34
+ end
35
+
36
+ sig { returns(T::Array[PredicatePipeline::PredicateConfig]) }
37
+ def pipeline
38
+ predicate_pipeline.pipeline.reject do |predicate_config|
39
+ unsupported_fields.include?(predicate_config.field)
40
+ end
41
+ end
42
+
43
+ sig { returns(T.nilable(FullAddressValidatorBase)) }
44
+ def full_address_validator
45
+ predicate_pipeline.full_address_validator&.new(
46
+ address: address,
47
+ result: result,
48
+ message_format: message_format,
49
+ )
50
+ end
51
+
52
+ sig do
53
+ returns(T::Array[Symbol])
54
+ end
55
+ def unsupported_fields
56
+ @unsupported_fields ||= T.let(
57
+ begin
58
+ unsupported_fields = []
59
+ unsupported_fields += address1_format == :extended ? [:address1] : [:street_name, :street_number]
60
+ unsupported_fields += address2_format == :extended ? [:address2] : [:line2, :neighborhood]
61
+ unsupported_fields
62
+ end,
63
+ T.nilable(T::Array[T.untyped]),
64
+ )
65
+ end
66
+
67
+ private
68
+
69
+ sig { returns(Symbol) }
70
+ def address1_format
71
+ T.let(
72
+ [:street_name, :street_number].all? do |field|
73
+ address.send(field).nil?
74
+ end ? :standard : :extended,
75
+ Symbol,
76
+ )
77
+ end
78
+
79
+ sig { returns(Symbol) }
80
+ def address2_format
81
+ T.let(
82
+ [:neighborhood, :line2].all? do |field|
83
+ address.send(field).nil?
84
+ end ? :standard : :extended,
85
+ Symbol,
86
+ )
87
+ end
88
+ end
89
+ end
90
+ end
@@ -7,6 +7,7 @@ module AtlasEngine
7
7
  const :address, AbstractAddress
8
8
  const :locale, String, default: "en"
9
9
  const :matching_strategy, T.nilable(T.any(String, Symbol)), default: nil
10
+ const :message_format, T.nilable(T.any(String, Symbol)), default: nil
10
11
  end
11
12
  end
12
13
  end
@@ -12,9 +12,21 @@ module AtlasEngine
12
12
  sig { returns(T.nilable(String)) }
13
13
  attr_accessor :address1
14
14
 
15
+ sig { returns(T.nilable(String)) }
16
+ attr_accessor :street_name
17
+
18
+ sig { returns(T.nilable(String)) }
19
+ attr_accessor :street_number
20
+
15
21
  sig { returns(T.nilable(String)) }
16
22
  attr_accessor :address2
17
23
 
24
+ sig { returns(T.nilable(String)) }
25
+ attr_accessor :line2
26
+
27
+ sig { returns(T.nilable(String)) }
28
+ attr_accessor :neighborhood
29
+
18
30
  sig { returns(T.nilable(String)) }
19
31
  attr_accessor :city
20
32
 
@@ -30,16 +42,25 @@ module AtlasEngine
30
42
  sig do
31
43
  params(
32
44
  address1: T.nilable(String),
45
+ street_name: T.nilable(String),
46
+ street_number: T.nilable(String),
33
47
  address2: T.nilable(String),
48
+ line2: T.nilable(String),
49
+ neighborhood: T.nilable(String),
34
50
  city: T.nilable(String),
35
51
  zip: T.nilable(String),
36
52
  province_code: T.nilable(String),
37
53
  country_code: T.nilable(String),
38
54
  ).void
39
55
  end
40
- def initialize(address1: nil, address2: nil, city: nil, zip: nil, province_code: nil, country_code: nil)
56
+ def initialize(address1: nil, street_name: nil, street_number: nil, address2: nil, line2: nil, neighborhood: nil,
57
+ city: nil, zip: nil, province_code: nil, country_code: nil)
41
58
  @address1 = address1
59
+ @street_name = street_name
60
+ @street_number = street_number
42
61
  @address2 = address2
62
+ @line2 = line2
63
+ @neighborhood = neighborhood
43
64
  @city = city
44
65
  @zip = zip
45
66
  @province_code = province_code
@@ -55,7 +76,11 @@ module AtlasEngine
55
76
  {
56
77
  id: id,
57
78
  address1: address1,
79
+ street_name: street_name,
80
+ street_number: street_number,
58
81
  address2: address2,
82
+ line2: line2,
83
+ neighborhood: neighborhood,
59
84
  city: city,
60
85
  zip: zip,
61
86
  province_code: province_code,
@@ -28,6 +28,12 @@ module AtlasEngine
28
28
  sig { returns(T.nilable(FullAddressValidatorBase)) }
29
29
  attr_reader :full_address_validator
30
30
 
31
+ sig { returns(T::Array[Symbol]) }
32
+ attr_reader :unsupported_fields
33
+
34
+ sig { returns(MessageFormat) }
35
+ attr_reader :message_format
36
+
31
37
  FIELD_MAP = T.let(
32
38
  {
33
39
  country: "country_code",
@@ -36,6 +42,10 @@ module AtlasEngine
36
42
  city: "city",
37
43
  address1: "address1",
38
44
  address2: "address2",
45
+ street_name: "street_name",
46
+ street_number: "street_number",
47
+ neighborhood: "neighborhood",
48
+ line2: "line2",
39
49
  phone: "phone",
40
50
  },
41
51
  T::Hash[Symbol, String],
@@ -47,13 +57,15 @@ module AtlasEngine
47
57
  matching_strategy: Strategies,
48
58
  locale: String,
49
59
  context: T::Hash[T.untyped, T.untyped],
60
+ message_format: MessageFormat,
50
61
  ).void
51
62
  end
52
63
  def initialize(
53
64
  address:,
54
65
  matching_strategy:,
55
66
  locale: "en",
56
- context: {}
67
+ context: {},
68
+ message_format: MessageFormat::Instructional
57
69
  )
58
70
  @address = T.let(address, AbstractAddress)
59
71
  @address1 = T.let(address.address1, T.nilable(String))
@@ -65,9 +77,9 @@ module AtlasEngine
65
77
  @country_code = T.let(address.country_code, T.nilable(String))
66
78
  @context = T.let(context, T::Hash[T.untyped, T.untyped])
67
79
  @matching_strategy = T.let(matching_strategy, Strategies)
80
+ @message_format = T.let(message_format, MessageFormat)
68
81
 
69
82
  matching_strategy_name = matching_strategy.serialize
70
- @predicate_pipeline = T.let(PredicatePipeline.find(matching_strategy_name), PredicatePipeline)
71
83
 
72
84
  @result = T.let(
73
85
  Result.new(
@@ -78,14 +90,14 @@ module AtlasEngine
78
90
  ),
79
91
  Result,
80
92
  )
93
+ pipeline_builder = PredicatePipelineBuilder.new(matching_strategy_name:, address:, result:, message_format:)
81
94
 
82
- @full_address_validator = T.let(
83
- @predicate_pipeline.full_address_validator&.new(
84
- address: @address,
85
- result: @result,
86
- ),
87
- T.nilable(FullAddressValidatorBase),
95
+ @pipeline = T.let(
96
+ pipeline_builder.pipeline,
97
+ T::Array[AtlasEngine::AddressValidation::PredicatePipeline::PredicateConfig],
88
98
  )
99
+ @unsupported_fields = T.let(pipeline_builder.unsupported_fields, T::Array[Symbol])
100
+ @full_address_validator = T.let(pipeline_builder.full_address_validator, T.nilable(FullAddressValidatorBase))
89
101
  end
90
102
 
91
103
  sig { override.returns(Result) }
@@ -113,15 +125,20 @@ module AtlasEngine
113
125
  pipeline_address = Address.from_address(address: address)
114
126
  local_concerns = {}
115
127
  cache = Validators::Predicates::Cache.new(pipeline_address)
116
- @predicate_pipeline.pipeline.each do |config|
128
+ @pipeline.each do |predicate_config|
117
129
  break if local_concerns[:country].present?
118
130
 
119
- local_concerns[config.field] = [] if local_concerns[config.field].nil?
120
- next if local_concerns[config.field].present?
131
+ local_concerns[predicate_config.field] = [] if local_concerns[predicate_config.field].nil?
132
+ next if local_concerns[predicate_config.field].present?
121
133
 
122
- concern = config.class_name.new(field: config.field, address: pipeline_address, cache: cache).evaluate
134
+ concern = predicate_config.class_name.new(
135
+ field: predicate_config.field,
136
+ address: pipeline_address,
137
+ cache: cache,
138
+ message_format: message_format,
139
+ ).evaluate
123
140
 
124
- local_concerns[config.field] << concern if concern.present?
141
+ local_concerns[predicate_config.field] << concern if concern.present?
125
142
  end
126
143
  local_concerns
127
144
  end
@@ -129,7 +146,7 @@ module AtlasEngine
129
146
  sig { params(local_concerns: T::Hash[Symbol, T::Array[Concern]]).void }
130
147
  def populate_result(local_concerns)
131
148
  local_concerns.keys.each do |field|
132
- if local_concerns[field]&.empty? && [:address2, :phone].exclude?(field)
149
+ if local_concerns[field]&.empty? && [:address2, :phone].concat(unsupported_fields).exclude?(field)
133
150
  result.validation_scope << T.must(FIELD_MAP[field])
134
151
  end
135
152
 
@@ -14,10 +14,11 @@ module AtlasEngine
14
14
  address_comparison: AddressComparison,
15
15
  matching_strategy: AddressValidation::MatchingStrategies,
16
16
  result: Result,
17
+ message_format: MessageFormat,
17
18
  ).void
18
19
  end
19
- def initialize(address_comparison:, matching_strategy:, result:)
20
- super(address: address_comparison.address, result: result)
20
+ def initialize(address_comparison:, matching_strategy:, result:, message_format:)
21
+ super(address: address_comparison.address, result: result, message_format: message_format)
21
22
  @address_comparison = address_comparison
22
23
  @candidate = address_comparison.candidate
23
24
  @matching_strategy = matching_strategy
@@ -56,11 +57,11 @@ module AtlasEngine
56
57
 
57
58
  sig { void }
58
59
  def add_concerns_without_suggestions
59
- concern = InvalidZipConcernBuilder.for(address, [])
60
+ concern = InvalidZipConcernBuilder.for(address, [], message_format)
60
61
  result.concerns << concern if concern
61
62
 
62
63
  if ConcernBuilder.too_many_unmatched_components?(address, unmatched_components.keys)
63
- result.concerns << UnknownAddressConcernBuilder.new(address).build
64
+ result.concerns << UnknownAddressConcernBuilder.new(address, message_format).build
64
65
  end
65
66
  end
66
67
 
@@ -79,6 +80,7 @@ module AtlasEngine
79
80
  matched_components: matched_components_to_validate.keys,
80
81
  address: address,
81
82
  suggestion_ids: [suggestion.id].compact,
83
+ message_format: message_format,
82
84
  ).build
83
85
  result.concerns << concern
84
86
  end
@@ -167,7 +169,9 @@ module AtlasEngine
167
169
 
168
170
  original_street = T.must(unmatched_components_to_validate[:street]).left_sequence.raw_value
169
171
 
170
- if address.address1.to_s.include?(original_street)
172
+ if address.street_name.present?
173
+ :street_name
174
+ elsif address.address1.to_s.include?(original_street)
171
175
  :address1
172
176
  elsif address.address2.to_s.include?(original_street)
173
177
  :address2
@@ -11,10 +11,11 @@ module AtlasEngine
11
11
 
12
12
  abstract!
13
13
 
14
- sig { params(address: AbstractAddress, result: Result).void }
15
- def initialize(address:, result:)
14
+ sig { params(address: AbstractAddress, result: Result, message_format: MessageFormat).void }
15
+ def initialize(address:, result:, message_format: MessageFormat::Instructional)
16
16
  @address = address
17
17
  @result = result
18
+ @message_format = message_format
18
19
  end
19
20
 
20
21
  sig { void }
@@ -22,7 +23,7 @@ module AtlasEngine
22
23
 
23
24
  private
24
25
 
25
- attr_reader :result, :address
26
+ attr_reader :result, :address, :message_format
26
27
 
27
28
  sig { void }
28
29
  def update_result_scope
@@ -8,7 +8,12 @@ module AtlasEngine
8
8
  class ConcernBuilder
9
9
  extend T::Sig
10
10
 
11
- attr_reader :unmatched_component, :unmatched_field, :matched_components, :address, :suggestion_ids
11
+ attr_reader :unmatched_component,
12
+ :unmatched_field,
13
+ :matched_components,
14
+ :address,
15
+ :suggestion_ids,
16
+ :message_format
12
17
 
13
18
  class << self
14
19
  extend T::Sig
@@ -79,15 +84,24 @@ module AtlasEngine
79
84
  matched_components: T::Array[Symbol],
80
85
  address: AbstractAddress,
81
86
  suggestion_ids: T::Array[String],
87
+ message_format: MessageFormat,
82
88
  unmatched_field: T.nilable(Symbol),
83
89
  ).void
84
90
  end
85
- def initialize(unmatched_component:, matched_components:, address:, suggestion_ids:, unmatched_field: nil)
91
+ def initialize(
92
+ unmatched_component:,
93
+ matched_components:,
94
+ address:,
95
+ suggestion_ids:,
96
+ message_format:,
97
+ unmatched_field: nil
98
+ )
86
99
  @unmatched_component = unmatched_component
87
100
  @unmatched_field = unmatched_field
88
101
  @matched_components = matched_components
89
102
  @address = address
90
103
  @suggestion_ids = suggestion_ids
104
+ @message_format = message_format
91
105
  end
92
106
 
93
107
  sig { returns(AddressValidation::Concern) }
@@ -106,7 +120,7 @@ module AtlasEngine
106
120
 
107
121
  sig { returns(AddressValidation::Concern) }
108
122
  def build_zip_concern
109
- concern = InvalidZipConcernBuilder.for(address, suggestion_ids)
123
+ concern = InvalidZipConcernBuilder.for(address, suggestion_ids, message_format)
110
124
  return concern if concern
111
125
 
112
126
  build_default_concern
@@ -115,7 +129,7 @@ module AtlasEngine
115
129
  sig { returns(AddressValidation::Concern) }
116
130
  def build_province_concern
117
131
  if ([:zip, :city] - matched_components).empty?
118
- UnknownProvinceConcernBuilder.new(address).build(suggestion_ids)
132
+ UnknownProvinceConcernBuilder.new(address, message_format).build(suggestion_ids)
119
133
  else
120
134
  build_default_concern
121
135
  end
@@ -128,6 +142,7 @@ module AtlasEngine
128
142
  matched_components,
129
143
  address,
130
144
  unmatched_field,
145
+ message_format,
131
146
  ).build(suggestion_ids)
132
147
  end
133
148
  end
@@ -13,9 +13,10 @@ module AtlasEngine
13
13
  params(
14
14
  address: AbstractAddress,
15
15
  suggestion_ids: T::Array[String],
16
+ message_format: MessageFormat,
16
17
  ).returns(T.nilable(AddressValidation::Concern))
17
18
  end
18
- def for(address, suggestion_ids)
19
+ def for(address, suggestion_ids, message_format)
19
20
  country = Worldwide.region(code: address.country_code)
20
21
 
21
22
  province = country.zone(code: address.province_code.presence || "")
@@ -24,11 +25,11 @@ module AtlasEngine
24
25
  if country_expects_zone_in_address?(country) && province.province?
25
26
  return if province.valid_zip?(address.zip)
26
27
 
27
- InvalidZipForProvinceConcernBuilder.new(address).build
28
+ InvalidZipForProvinceConcernBuilder.new(address, message_format).build
28
29
  else
29
30
  return if country.valid_zip?(address.zip)
30
31
 
31
- InvalidZipForCountryConcernBuilder.new(address).build(suggestion_ids)
32
+ InvalidZipForCountryConcernBuilder.new(address, message_format).build(suggestion_ids)
32
33
  end
33
34
  end
34
35
 
@@ -9,16 +9,18 @@ module AtlasEngine
9
9
  extend T::Sig
10
10
  include ConcernFormatter
11
11
  attr_reader :address
12
+ attr_reader :message_format
12
13
 
13
- sig { params(address: AbstractAddress).void }
14
- def initialize(address)
14
+ sig { params(address: AbstractAddress, message_format: MessageFormat).void }
15
+ def initialize(address, message_format)
15
16
  @address = address
17
+ @message_format = message_format
16
18
  end
17
19
 
18
20
  sig { params(suggestion_ids: T::Array[String]).returns(Concern) }
19
21
  def build(suggestion_ids = [])
20
- message = country.field(key: :zip).error(
21
- code: :invalid_for_country,
22
+ message = country.field(key: :zip).error(
23
+ code: "invalid_for_country_#{message_format.serialize}".to_sym,
22
24
  options: { country: country.full_name },
23
25
  ).to_s
24
26
 
@@ -9,15 +9,17 @@ module AtlasEngine
9
9
  extend T::Sig
10
10
  include ConcernFormatter
11
11
  attr_reader :address
12
+ attr_reader :message_format
12
13
 
13
- def initialize(address)
14
+ def initialize(address, message_format)
14
15
  @address = address
16
+ @message_format = message_format
15
17
  end
16
18
 
17
19
  sig { params(suggestion_ids: T::Array[String]).returns(Concern) }
18
20
  def build(suggestion_ids = [])
19
21
  message = country.field(key: :zip).error(
20
- code: :invalid_for_province,
22
+ code: "invalid_for_province_#{message_format.serialize}".to_sym,
21
23
  options: { province: province_name },
22
24
  ).to_s
23
25
 
@@ -12,7 +12,7 @@ module AtlasEngine
12
12
  def update_result
13
13
  result.concerns << UnknownAddressConcernBuilder.new(address).build
14
14
 
15
- concern = InvalidZipConcernBuilder.for(address, [])
15
+ concern = InvalidZipConcernBuilder.for(address, [], message_format)
16
16
  result.concerns << concern if concern
17
17
 
18
18
  update_result_scope
@@ -12,7 +12,11 @@ module AtlasEngine
12
12
  params(
13
13
  address: {
14
14
  address1: T.nilable(String),
15
+ street_name: T.nilable(String),
16
+ street_number: T.nilable(String),
15
17
  address2: T.nilable(String),
18
+ line2: T.nilable(String),
19
+ neighborhood: T.nilable(String),
16
20
  city: T.nilable(String),
17
21
  province_code: T.nilable(String),
18
22
  country_code: T.nilable(String),
@@ -70,9 +74,12 @@ module AtlasEngine
70
74
  original_street = comparison.left_sequence.raw_value
71
75
  field = unmatched_fields[:street]
72
76
 
73
- if field == :address1
77
+ case field
78
+ when :street_name
79
+ suggestion.street_name = suggested_street
80
+ when :address1
74
81
  suggestion.address1 = suggestion.address1.to_s.sub(original_street, suggested_street)
75
- elsif field == :address2
82
+ when :address2
76
83
  suggestion.address2 = suggestion.address2.to_s.sub(original_street, suggested_street)
77
84
  end
78
85
 
@@ -12,14 +12,20 @@ module AtlasEngine
12
12
  sig { returns(TAddress) }
13
13
  attr_reader :address
14
14
 
15
- sig { params(address: TAddress).void }
16
- def initialize(address)
15
+ sig { returns(MessageFormat) }
16
+ attr_reader :message_format
17
+
18
+ sig { params(address: TAddress, message_format: MessageFormat).void }
19
+ def initialize(address, message_format = MessageFormat::Instructional)
17
20
  @address = address
21
+ @message_format = message_format
18
22
  end
19
23
 
20
24
  sig { params(suggestion_ids: T::Array[String]).returns(Concern) }
21
25
  def build(suggestion_ids = [])
22
- message = country.field(key: :address).error(code: :may_not_exist)
26
+ message = country.field(key: :address).error(
27
+ code: "may_not_exist_#{message_format.serialize}".to_sym,
28
+ ).to_s
23
29
 
24
30
  Concern.new(
25
31
  code: :address_unknown,
@@ -27,9 +33,15 @@ module AtlasEngine
27
33
  type: T.must(Concern::TYPES[:warning]),
28
34
  type_level: 1,
29
35
  suggestion_ids: suggestion_ids,
30
- field_names: [:address1],
36
+ field_names: [field],
31
37
  )
32
38
  end
39
+
40
+ private
41
+
42
+ def field
43
+ address.street_name.present? ? :street_name : :address1
44
+ end
33
45
  end
34
46
  end
35
47
  end
@@ -8,17 +8,22 @@ module AtlasEngine
8
8
  class UnknownProvinceConcernBuilder
9
9
  extend T::Sig
10
10
  include ConcernFormatter
11
+
11
12
  attr_reader :address
12
13
 
13
- sig { params(address: AbstractAddress).void }
14
- def initialize(address)
14
+ sig { returns(MessageFormat) }
15
+ attr_reader :message_format
16
+
17
+ sig { params(address: AbstractAddress, message_format: MessageFormat).void }
18
+ def initialize(address, message_format = MessageFormat::Instructional)
15
19
  @address = address
20
+ @message_format = message_format
16
21
  end
17
22
 
18
23
  sig { params(suggestion_ids: T::Array[String]).returns(Concern) }
19
24
  def build(suggestion_ids = [])
20
25
  message = country.field(key: :province).error(
21
- code: :unknown_for_city_and_zip,
26
+ code: "unknown_for_city_and_zip_#{message_format.serialize}".to_sym,
22
27
  options: { city: address.city, zip: address.zip },
23
28
  ).to_s
24
29
 
@@ -8,7 +8,7 @@ module AtlasEngine
8
8
  class UnmatchedFieldConcernBuilder
9
9
  extend T::Sig
10
10
  include ConcernFormatter
11
- attr_reader :address, :unmatched_component, :matched_components, :unmatched_field
11
+ attr_reader :address, :unmatched_component, :matched_components, :unmatched_field, :message_format
12
12
 
13
13
  COMPONENTS_TO_LABELS = {
14
14
  zip: "ZIP",
@@ -27,13 +27,21 @@ module AtlasEngine
27
27
  matched_components: T::Array[Symbol],
28
28
  address: AbstractAddress,
29
29
  unmatched_field: T.nilable(Symbol),
30
+ message_format: MessageFormat,
30
31
  ).void
31
32
  end
32
- def initialize(unmatched_component, matched_components, address, unmatched_field = nil)
33
+ def initialize(
34
+ unmatched_component,
35
+ matched_components,
36
+ address,
37
+ unmatched_field = nil,
38
+ message_format = MessageFormat::Instructional
39
+ )
33
40
  @address = address
34
41
  @unmatched_component = unmatched_component
35
42
  @matched_components = matched_components
36
43
  @unmatched_field = unmatched_field || unmatched_component
44
+ @message_format = message_format
37
45
  end
38
46
 
39
47
  sig do
@@ -56,7 +64,9 @@ module AtlasEngine
56
64
 
57
65
  sig { returns(String) }
58
66
  def message
59
- country.field(key: field_name).error(code: :unknown_for_address).to_s
67
+ country.field(key: field_name).error(
68
+ code: "unknown_for_address_#{message_format.serialize}".to_sym,
69
+ ).to_s
60
70
  end
61
71
 
62
72
  sig { returns(Symbol) }
@@ -10,7 +10,7 @@ module AtlasEngine
10
10
 
11
11
  sig { void }
12
12
  def update_result
13
- concern = InvalidZipConcernBuilder.for(address, [])
13
+ concern = InvalidZipConcernBuilder.for(address, [], message_format)
14
14
  result.concerns << concern if concern
15
15
 
16
16
  update_result_scope
@@ -24,7 +24,7 @@ module AtlasEngine
24
24
  type: T.must(Concern::TYPES[:error]),
25
25
  type_level: 3,
26
26
  suggestion_ids: [],
27
- message: @cache.country.field(key: :city).error(code: :blank).to_s,
27
+ message: @cache.country.field(key: :city).error(code: "blank_#{message_format.serialize}".to_sym).to_s,
28
28
  )
29
29
  end
30
30
  end
@@ -23,7 +23,11 @@ module AtlasEngine
23
23
  type: T.must(Concern::TYPES[:error]),
24
24
  type_level: 3,
25
25
  suggestion_ids: [],
26
- message: Worldwide.region(code: "US").field(key: :country).error(code: :blank),
26
+ message: Worldwide
27
+ .region(code: "US")
28
+ .field(key: :country)
29
+ .error(code: "blank_#{message_format.serialize}".to_sym)
30
+ .to_s,
27
31
  )
28
32
  end
29
33
  end
@@ -34,7 +34,7 @@ module AtlasEngine
34
34
  type_level: 1,
35
35
  suggestion_ids: [T.must(suggestion.id)],
36
36
  message: @cache.country.field(key: :zip).error(
37
- code: :invalid_for_country,
37
+ code: "invalid_for_country_#{message_format.serialize}".to_sym,
38
38
  options: { country: @cache.country.full_name },
39
39
  ),
40
40
  suggestion: suggestion,