costa_rica_address_utils 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,101 @@
1
+ require 'json'
2
+
3
+ # TODO: find way to optimize dataset loading
4
+
5
+ module CostaRicaAddressUtils
6
+ module CostaRica
7
+ JSON_FILE_PATH = File.join(File.dirname(__FILE__), '..', '..', 'data', 'locations_dataset.json')
8
+ NEW_JSON_FILE_PATH = File.join(File.dirname(__FILE__), '..', '..', 'data', 'costa_rica_dataset.json')
9
+
10
+ # Load the JSON file and parse it into a Ruby object for general usage
11
+ LOCATIONS_DATASET = JSON.parse(File.read(JSON_FILE_PATH))
12
+ NEW_LOCATIONS_DATASET = JSON.parse(File.read(NEW_JSON_FILE_PATH)) # Should replace locations_dataset.json in the future
13
+
14
+ class Error < StandardError; end
15
+ # Your code goes here...
16
+
17
+ # Fetch the address data from provided input, return options for subaddresses on each level and zip code if full address is valid
18
+ def fetch_address_data(province:, canton: nil, district: nil)
19
+ raise CostaRicaAddressUtils::InvalidData, 'Province is required' if province.nil? || province.empty?
20
+
21
+ province_data = LOCATIONS_DATASET[province]
22
+ canton_data = !!province_data ? province_data['cantons'][canton] : nil
23
+ district_data = !!canton_data ? canton_data['districts'][district] : nil
24
+
25
+ canton_options = !!province_data ? province_data['cantons'].keys : [] # Cantons options, only if province is valid
26
+ district_options = !!canton_data ? canton_data['districts'].keys : [] # Districts options, only if canton is valid
27
+ zip = (!!district_data && district_data['zip_code']) || nil # Zip code, only if full address is valid
28
+
29
+ {
30
+ zip: zip,
31
+ # Names options
32
+ province_options: LOCATIONS_DATASET.keys,
33
+ canton_options: canton_options,
34
+ district_options: district_options
35
+ }
36
+ end
37
+
38
+ # Get one address information from a zip code
39
+ def fetch_address_from_zip(zip_code, new_dataset: false)
40
+ return nil unless zip_valid?(zip_code)
41
+
42
+ zip_code_s = zip_code.to_s
43
+
44
+ if new_dataset
45
+ NEW_LOCATIONS_DATASET.each do |province, province_data|
46
+ province_data['locationsLevel2'].each do |canton, canton_data|
47
+ canton_data['locationsLevel3'].each do |district, district_data|
48
+ if district_data['zipCode'] == zip_code_s
49
+ return {
50
+ province: province,
51
+ canton: canton,
52
+ district: district,
53
+ zip: zip_code_s
54
+ }
55
+ end
56
+ end
57
+ end
58
+ end
59
+ else
60
+ LOCATIONS_DATASET.each do |province, province_data|
61
+ province_data['cantons'].each do |canton, canton_data|
62
+ canton_data['districts'].each do |district, district_data|
63
+ if district_data['zip_code'] == zip_code_s
64
+ return {
65
+ province: province,
66
+ canton: canton,
67
+ district: district,
68
+ zip: zip_code_s
69
+ }
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ nil
77
+ end
78
+
79
+ def fetch_address_from_zip!(zip_code, new_dataset: false)
80
+ raise "Zip code provided #{zip_code} is invalid. Must be a 5 digits number" unless zip_valid?(zip_code)
81
+
82
+ fetch_address_from_zip(zip_code, new_dataset: new_dataset)
83
+ end
84
+
85
+ def address_valid?(province:, canton:, district:)
86
+ is_valid = true
87
+ begin
88
+ data = fetch_address_data(province: province, canton: canton, district: district)
89
+ is_valid = !!data[:zip] # Is valid if matched to a zip code
90
+ rescue CostaRicaAddressUtils::InvalidData => e
91
+ is_valid = false
92
+ end
93
+
94
+ is_valid
95
+ end
96
+
97
+ def zip_valid?(zip_code)
98
+ !!zip_code && zip_code.to_s.length == 5
99
+ end
100
+ end # CostaRica
101
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CostaRicaAddressUtils
4
+ module Guatemala
5
+ # Guatemala-specific implementation
6
+ JSON_FILE_PATH = File.join(File.dirname(__FILE__), '..', '..', 'data', 'guatemala_dataset.json')
7
+ LOCATIONS_DATASET = JSON.parse(File.read(JSON_FILE_PATH))
8
+
9
+ # Your Guatemala-specific methods here
10
+
11
+ # For a given address of 2 levels, return options for each level found and zip code if full address is valid
12
+ def self.fetch_address_data(department:, municipality:)
13
+ raise CostaRicaAddressUtils::InvalidData, 'Department is required' if department.nil? || department.empty?
14
+
15
+ department_data = LOCATIONS_DATASET[department]
16
+ municipality_data = !!department_data ? department_data['locationsLevel2'][municipality] : nil
17
+
18
+ # Municipality options(lv2), only if department(lv1) is valid
19
+ municipality_options = !!department_data ? department_data['locationsLevel2'].keys : []
20
+ zip = (!!municipality_data && municipality_data['zipCode']) || nil # Zip code, only if full address is valid
21
+
22
+ {
23
+ zip: zip,
24
+ # Names options
25
+ department_options: LOCATIONS_DATASET.keys,
26
+ municipality_options: municipality_options
27
+ }
28
+ end
29
+
30
+ # Get one address information from a zip code
31
+ def self.fetch_address_from_zip(zip_code)
32
+ return nil unless zip_valid?(zip_code)
33
+
34
+ zip_code_s = zip_code.to_s
35
+ LOCATIONS_DATASET.each do |department, department_data|
36
+ department_data['locationsLevel2'].each do |municipality, municipality_data|
37
+ if municipality_data['zipCode'] == zip_code_s
38
+ return {
39
+ department: department,
40
+ municipality: municipality,
41
+ zip: zip_code_s
42
+ }
43
+ end
44
+ end
45
+ end
46
+
47
+ nil
48
+ end
49
+
50
+ def self.address_valid?(department:, municipality:)
51
+ is_valid = true
52
+ begin
53
+ data = fetch_address_data(department: department, municipality: municipality)
54
+ is_valid = !!data[:zip] # Is valid if matched to a zip code
55
+ rescue CostaRicaAddressUtils::InvalidData => e
56
+ is_valid = false
57
+ end
58
+
59
+ is_valid
60
+ end
61
+ end # Guatemala
62
+ end # CostaRicaAddressUtils
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CostaRicaAddressUtils
4
- VERSION = '0.3.2'
4
+ VERSION = '0.5.0'
5
5
  end
@@ -1,118 +1,67 @@
1
1
  # frozen_string_literal: true
2
- # TODO find way to optimize dataset loading
3
- require 'json'
4
- require_relative "costa_rica_address_utils/version"
5
- require_relative "costa_rica_address_utils/errors"
6
2
 
7
- JSON_FILE_PATH = File.join(File.dirname(__FILE__), '..', 'data', 'locations_dataset.json')
3
+ require_relative 'costa_rica_address_utils/version'
4
+ require_relative 'costa_rica_address_utils/errors'
5
+ require_relative 'costa_rica_address_utils/costa_rica'
6
+ require_relative 'costa_rica_address_utils/guatemala'
8
7
 
9
- module CostaRicaAddressUtils
10
- # Load the JSON file and parse it into a Ruby object for general usage
11
- LOCATIONS_DATASET = JSON.parse(File.read(JSON_FILE_PATH))
12
- VAlID_PROVIDERS = [:shopify, :brightpearl]
8
+ module CostaRicaAddressUtils # rubocop:disable Style/Documentation
9
+ # Backwards compatibility before usage of for_country
10
+ # Old version will be able to call methods with CostaRicaAddressUtils directly
11
+ extend CostaRicaAddressUtils::CostaRica
13
12
 
14
- class Error < StandardError; end
15
- # Your code goes here...
13
+ SUPPORTED_COUNTRIES = %i[costa_rica guatemala].freeze
14
+ VALID_INPUT_PROVIDERS = %i[shopify brightpearl].freeze
16
15
 
17
- # Fetch the address data from provided input, return options for subaddresses on each level and zip code if full address is valid
18
- def self.fetch_address_data(province:, canton: nil, district: nil)
19
- raise InvalidData, "Province is required" if province.nil? || province.empty?
16
+ # TODO: merge the methods from both countries using new dataset for costa rica instead of previous one
17
+ # Newer files contains a standarized format for fields.
20
18
 
21
- province_data = LOCATIONS_DATASET[province]
22
- canton_data = !!province_data ? province_data["cantons"][canton] : nil
23
- district_data = !!canton_data ? canton_data["districts"][district] : nil
24
-
25
- canton_options = !!province_data ? province_data["cantons"].keys : [] # Cantons options, only if province is valid
26
- district_options = !!canton_data ? canton_data["districts"].keys : [] # Districts options, only if canton is valid
27
- zip = (!!district_data && district_data["zip_code"]) || nil # Zip code, only if full address is valid
28
-
29
- return {
30
- zip: zip,
31
- # Names options
32
- province_options: LOCATIONS_DATASET.keys,
33
- canton_options: canton_options,
34
- district_options: district_options,
35
- }
36
- end
37
-
38
- # Get one address information from a zip code
39
- def self.fetch_address_from_zip(zip_code)
40
- return nil unless zip_valid?(zip_code)
41
- zip_code_s = zip_code.to_s
42
- LOCATIONS_DATASET.each do |province, province_data|
43
- province_data["cantons"].each do |canton, canton_data|
44
- canton_data["districts"].each do |district, district_data|
45
- if district_data["zip_code"] == zip_code_s
46
- return {
47
- province: province,
48
- canton: canton,
49
- district: district,
50
- zip: zip_code_s,
51
- }
52
- end
53
- end
54
- end
55
- end
56
-
57
- return nil
58
- end
59
-
60
- def self.fetch_address_from_zip!(zip_code)
61
- raise "Zip code provided #{zip_code} is invalid. Must be a 5 digits number" unless zip_valid?(zip_code)
62
- fetch_address_from_zip(zip_code)
63
- end
64
-
65
- def self.address_valid?(province:, canton:, district:)
66
- is_valid = true
67
- begin
68
- data = fetch_address_data(province: province, canton: canton, district: district)
69
- is_valid = !!data[:zip] # Is valid if matched to a zip code
70
- rescue InvalidData => e
71
- is_valid = false
19
+ def self.for_country(country)
20
+ case country.to_sym
21
+ when :costa_rica
22
+ CostaRicaAddressUtils::CostaRica
23
+ when :guatemala
24
+ CostaRicaAddressUtils::Guatemala
25
+ else
26
+ raise ArgumentError, "Unsupported country: #{country}. Supported countries are: #{SUPPORTED_COUNTRIES}"
72
27
  end
73
-
74
- return is_valid
75
- end
76
-
77
- def self.zip_valid?(zip_code)
78
- !!zip_code && zip_code.to_s.length == 5
79
28
  end
80
29
 
81
30
  # Build a Costa Rica address from an address of an external provider (Shopify, Brightpearl, etc)
82
31
  # https://shopify.dev/api/admin-graphql/2022-10/objects/mailingaddress
83
32
  # https://api-docs.brightpearl.com/contact/postal-address/get.html
84
- def self.build_address_from_provider(address:, provider:)
33
+ # Standarized format locationLevelX for the address Province/Department, Municipality/Canton, District/Parish
34
+ # since they are named differently in each country
35
+ def self.build_address_from_provider(address:, provider:)
85
36
  case provider
86
37
  when :shopify
87
- return {
38
+ {
88
39
  name: address.name, # Customer name
89
40
  address1: address.address1,
90
-
91
- province: address.province,
92
- canton: address.city,
93
- district: address.address2,
41
+
42
+ locationLevel1: address.province,
43
+ locationLevel2: address.city,
44
+ locationLevel3: address.address2,
94
45
  zip: address.zip,
95
46
 
96
47
  national_id: address.company,
97
- phone: address.phone,
48
+ phone: address.phone
98
49
  }
99
50
  when :brightpearl
100
- return {
101
- name: address["addressFullName"], # Customer name
102
- address1: address["addressLine1"],
103
-
104
- province: address["addressLine4"],
105
- canton: address["addressLine3"],
106
- district: address["addressLine2"],
107
- zip: address["postalCode"],
51
+ {
52
+ name: address['addressFullName'], # Customer name
53
+ address1: address['addressLine1'],
108
54
 
109
- national_id: address["companyName"],
110
- phone: address["telephone"],
55
+ locationLevel1: address['addressLine4'],
56
+ locationLevel2: address['addressLine3'],
57
+ locationLevel3: address['addressLine2'],
58
+ zip: address['postalCode'],
59
+
60
+ national_id: address['companyName'],
61
+ phone: address['telephone']
111
62
  }
112
63
  else
113
- raise InvalidData("Invalid provider, valid providers are: #{VAlID_PROVIDERS}")
64
+ raise InvalidData("Invalid provider, valid providers are: #{VALID_INPUT_PROVIDERS}")
114
65
  end
115
66
  end
116
-
117
- private
118
- end # module CostaRicaAddressUtils
67
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: costa_rica_address_utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - vicvans20
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-21 00:00:00.000000000 Z
11
+ date: 2025-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -45,7 +45,9 @@ files:
45
45
  - data/guatemala_dataset.json
46
46
  - data/locations_dataset.json
47
47
  - lib/costa_rica_address_utils.rb
48
+ - lib/costa_rica_address_utils/costa_rica.rb
48
49
  - lib/costa_rica_address_utils/errors.rb
50
+ - lib/costa_rica_address_utils/guatemala.rb
49
51
  - lib/costa_rica_address_utils/version.rb
50
52
  - sig/costa_rica_address_utils.rbs
51
53
  homepage: https://github.com/vicvans20/costa_rica_address_utils