belpost 0.4.0 → 0.9.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +45 -0
- data/README.md +21 -0
- data/belpost.gemspec +1 -0
- data/lib/belpost/api_paths.rb +25 -0
- data/lib/belpost/api_service.rb +4 -3
- data/lib/belpost/client.rb +108 -4
- data/lib/belpost/configuration.rb +25 -2
- data/lib/belpost/models/batch.rb +42 -0
- data/lib/belpost/validations/address_schema.rb +30 -0
- data/lib/belpost/validations/batch_schema.rb +58 -0
- data/lib/belpost/validations/parcel_schema.rb +142 -124
- data/lib/belpost/version.rb +1 -1
- metadata +21 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9573611d63a9e36e61ada02613b8e8764fb2a45125a17f5938f2521b0a80586d
|
4
|
+
data.tar.gz: 1db61fe84045560aac6dc7e362aeb5698413851d23851c1b2601f84ca1ff6bc3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4ee356c1da9fad9db8b62a6d5bbe135c317b4c49cd818e856f8a81e70c8452dc98deeb03ffc59dd4d108efac8434c4ed1e9ce0ba5dcca41b23485f327255a26c
|
7
|
+
data.tar.gz: 40826b94cf8e911fc7930c5dae67412f4688ccc68f43bed53d5d5317d3146c848fd0f95111e24706cca2a5907b76d54fadf3d53c93eaa6a91aef8dc11f7190f9
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,50 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [0.9.0] - 2025-04-15
|
4
|
+
|
5
|
+
### Changed
|
6
|
+
- Refactored API paths into a separate module `Belpost::ApiPaths` for better maintainability
|
7
|
+
- Moved all hardcoded API endpoints into constants in `api_paths.rb`
|
8
|
+
- Updated all client methods to use the new API path constants
|
9
|
+
- Updated tests to use the new API path constants
|
10
|
+
|
11
|
+
### Added
|
12
|
+
- Added batch retrieval functionality via `find_batch_by_id` method
|
13
|
+
- Support for finding batch mailings by their ID with validation
|
14
|
+
- New module `Belpost::ApiPaths` with organized API endpoint constants:
|
15
|
+
- Batch mailing paths
|
16
|
+
- Postal deliveries paths
|
17
|
+
- Geo directory paths
|
18
|
+
|
19
|
+
## [0.8.0] - 2025-04-14
|
20
|
+
### Added
|
21
|
+
- Added batch mailing functionality via `create_batch` method
|
22
|
+
- Support for creating batch mailings with various delivery types
|
23
|
+
- Added comprehensive validation for batch mailing data
|
24
|
+
- Added new models and schemas for batch mailing
|
25
|
+
- Added tests for batch mailing functionality
|
26
|
+
|
27
|
+
## [0.7.0] - 2025-04-01
|
28
|
+
### Added
|
29
|
+
- Added postal code search functionality via `search_postcode` method
|
30
|
+
- Support for searching postal codes by city, street, and building number
|
31
|
+
- Added comprehensive tests for the new postal code search endpoint
|
32
|
+
|
33
|
+
## [0.6.0] - 2025-04-01
|
34
|
+
### Added
|
35
|
+
- Added search addresses search functionality via `find_address_by_string` method
|
36
|
+
|
37
|
+
## [0.5.1] - 2025-04-01
|
38
|
+
### Fixed
|
39
|
+
- Improved error handling for invalid timeout environment variable
|
40
|
+
- Added fallback for BELPOST_API_URL environment variable to make tests more robust
|
41
|
+
- Fixed Configuration class by implementing `validate!` and `to_h` methods
|
42
|
+
|
43
|
+
## [0.5.0] - 2025-04-01
|
44
|
+
### Added
|
45
|
+
- Added address search functionality via `find_address_by_string` method
|
46
|
+
- Support for query parameters in GET requests
|
47
|
+
|
3
48
|
## [0.4.0] - 2025-04-01
|
4
49
|
### Added
|
5
50
|
- Added configuration via environment variables
|
data/README.md
CHANGED
@@ -295,6 +295,27 @@ hs_codes = client.fetch_hs_codes
|
|
295
295
|
puts hs_codes
|
296
296
|
```
|
297
297
|
|
298
|
+
### Searching for postal codes
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
client = Belpost::Client.new
|
302
|
+
postcodes = client.search_postcode(
|
303
|
+
city: "Витебск",
|
304
|
+
street: "Ильинского",
|
305
|
+
building: "51/1", # optional
|
306
|
+
limit: 50 # optional, default: 50, range: 1-200
|
307
|
+
)
|
308
|
+
puts postcodes
|
309
|
+
```
|
310
|
+
|
311
|
+
### Finding a batch by ID
|
312
|
+
|
313
|
+
```ruby
|
314
|
+
client = Belpost::Client.new
|
315
|
+
batch = client.find_batch_by_id(123)
|
316
|
+
puts batch
|
317
|
+
```
|
318
|
+
|
298
319
|
## Error handling
|
299
320
|
|
300
321
|
The client may throw the following exceptions:
|
data/belpost.gemspec
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Belpost
|
4
|
+
# Constants for API paths
|
5
|
+
module ApiPaths
|
6
|
+
# Batch mailing paths
|
7
|
+
BATCH_MAILING_LIST = "/api/v1/business/batch-mailing/list"
|
8
|
+
BATCH_MAILING_DOCUMENTS = "/api/v1/business/batch-mailing/documents"
|
9
|
+
BATCH_MAILING_ITEM = "/api/v1/business/batch-mailing/item"
|
10
|
+
BATCH_MAILING_DUPLICATE = "/api/v1/business/batch-mailing/list/:id/duplicate"
|
11
|
+
BATCH_MAILING_DUPLICATE_FULL = "/api/v1/business/batch-mailing/list/:id/duplicate-full"
|
12
|
+
BATCH_MAILING_COMMIT = "/api/v1/business/batch-mailing/list/:id/commit"
|
13
|
+
BATCH_MAILING_GENERATE_BLANK = "/api/v1/business/batch-mailing/list/:id/generate-blank"
|
14
|
+
|
15
|
+
# Postal deliveries paths
|
16
|
+
POSTAL_DELIVERIES = "/api/v1/business/postal-deliveries"
|
17
|
+
POSTAL_DELIVERIES_HS_CODES = "/api/v1/business/postal-deliveries/hs-codes/list"
|
18
|
+
POSTAL_DELIVERIES_VALIDATION = "/api/v1/business/postal-deliveries/validation"
|
19
|
+
POSTAL_DELIVERIES_COUNTRIES = "/api/v1/business/postal-deliveries/countries"
|
20
|
+
|
21
|
+
# Geo directory paths
|
22
|
+
GEO_DIRECTORY_SEARCH_ADDRESS = "/api/v1/business/geo-directory/search-address"
|
23
|
+
GEO_DIRECTORY_POSTCODE = "/api/v1/business/geo-directory/postcode"
|
24
|
+
end
|
25
|
+
end
|
data/lib/belpost/api_service.rb
CHANGED
@@ -23,10 +23,12 @@ module Belpost
|
|
23
23
|
# Performs a GET request to the specified path.
|
24
24
|
#
|
25
25
|
# @param path [String] The API endpoint path.
|
26
|
+
# @param params [Hash] The query parameters (default: {}).
|
26
27
|
# @return [Models::ApiResponse] The parsed JSON response from the API.
|
27
|
-
def get(path)
|
28
|
+
def get(path, params = {})
|
28
29
|
Retry.with_retry do
|
29
30
|
uri = URI("#{@base_url}#{path}")
|
31
|
+
uri.query = URI.encode_www_form(params) unless params.empty?
|
30
32
|
request = Net::HTTP::Get.new(uri)
|
31
33
|
add_headers(request)
|
32
34
|
|
@@ -149,7 +151,6 @@ module Belpost
|
|
149
151
|
http = Net::HTTP.new(uri.host, uri.port)
|
150
152
|
http.use_ssl = true if uri.scheme == "https"
|
151
153
|
http.read_timeout = @timeout
|
152
|
-
|
153
154
|
begin
|
154
155
|
response = http.request(request)
|
155
156
|
handle_response(response)
|
@@ -189,7 +190,7 @@ module Belpost
|
|
189
190
|
|
190
191
|
def handle_response(response)
|
191
192
|
case response.code
|
192
|
-
when "200"
|
193
|
+
when "200", "201"
|
193
194
|
response
|
194
195
|
when "401", "403"
|
195
196
|
raise AuthenticationError.new(
|
data/lib/belpost/client.rb
CHANGED
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
require_relative "api_service"
|
4
4
|
require_relative "models/parcel"
|
5
|
+
require_relative "models/batch"
|
5
6
|
require_relative "models/api_response"
|
7
|
+
require_relative "validations/address_schema"
|
8
|
+
require_relative "validations/batch_schema"
|
9
|
+
require_relative "api_paths"
|
6
10
|
|
7
11
|
module Belpost
|
8
12
|
# Main client class for interacting with the BelPost API.
|
@@ -22,6 +26,23 @@ module Belpost
|
|
22
26
|
)
|
23
27
|
end
|
24
28
|
|
29
|
+
# Creates a new batch mailing by sending a POST request to the API.
|
30
|
+
#
|
31
|
+
# @param batch_data [Hash] The data for the batch mailing.
|
32
|
+
# @return [Hash] The parsed JSON response from the API.
|
33
|
+
# @raise [Belpost::InvalidRequestError] If the request data is invalid.
|
34
|
+
# @raise [Belpost::ApiError] If the API returns an error response.
|
35
|
+
def create_batch(batch_data)
|
36
|
+
validation_result = Validation::BatchSchema.new.call(batch_data)
|
37
|
+
unless validation_result.success?
|
38
|
+
raise ValidationError, "Invalid batch data: #{validation_result.errors.to_h}"
|
39
|
+
end
|
40
|
+
|
41
|
+
batch = Models::Batch.new(batch_data)
|
42
|
+
response = @api_service.post(ApiPaths::BATCH_MAILING_LIST, batch.to_h)
|
43
|
+
response.to_h
|
44
|
+
end
|
45
|
+
|
25
46
|
# Creates a new postal parcel by sending a POST request to the API.
|
26
47
|
#
|
27
48
|
# @param parcel_data [Hash] The data for the postal parcel.
|
@@ -35,7 +56,7 @@ module Belpost
|
|
35
56
|
end
|
36
57
|
|
37
58
|
parcel = Models::Parcel.new(parcel_data)
|
38
|
-
response = @api_service.post(
|
59
|
+
response = @api_service.post(ApiPaths::POSTAL_DELIVERIES, parcel.to_h)
|
39
60
|
response.to_h
|
40
61
|
end
|
41
62
|
|
@@ -44,7 +65,7 @@ module Belpost
|
|
44
65
|
# @return [Array<Hash>] The HS codes tree as an array of hashes.
|
45
66
|
# @raise [Belpost::ApiError] If the API returns an error response.
|
46
67
|
def fetch_hs_codes
|
47
|
-
response = @api_service.get(
|
68
|
+
response = @api_service.get(ApiPaths::POSTAL_DELIVERIES_HS_CODES)
|
48
69
|
response.to_h
|
49
70
|
end
|
50
71
|
|
@@ -55,7 +76,7 @@ module Belpost
|
|
55
76
|
# @raise [Belpost::ApiError] If the API returns an error response.
|
56
77
|
def validate_postal_delivery(country_code)
|
57
78
|
country_code = country_code.upcase
|
58
|
-
response = @api_service.get("
|
79
|
+
response = @api_service.get("#{ApiPaths::POSTAL_DELIVERIES_VALIDATION}/#{country_code}")
|
59
80
|
response.to_h
|
60
81
|
end
|
61
82
|
|
@@ -64,8 +85,91 @@ module Belpost
|
|
64
85
|
# @return [Hash] The parsed JSON response containing available countries.
|
65
86
|
# @raise [Belpost::ApiError] If the API returns an error response.
|
66
87
|
def fetch_available_countries
|
67
|
-
response = @api_service.get(
|
88
|
+
response = @api_service.get(ApiPaths::POSTAL_DELIVERIES_COUNTRIES)
|
68
89
|
response.to_h
|
69
90
|
end
|
91
|
+
|
92
|
+
# Finds a batch by its ID.
|
93
|
+
#
|
94
|
+
# @param id [Integer] The ID of the batch to find.
|
95
|
+
# @return [Hash] The batch data if found.
|
96
|
+
# @raise [Belpost::ApiError] If the API returns an error response.
|
97
|
+
def find_batch_by_id(id)
|
98
|
+
raise ValidationError, "ID must be provided" if id.nil?
|
99
|
+
raise ValidationError, "ID must be a positive integer" unless id.is_a?(Integer) && id.positive?
|
100
|
+
|
101
|
+
response = @api_service.get("#{ApiPaths::BATCH_MAILING_LIST}/#{id}")
|
102
|
+
response.to_h
|
103
|
+
end
|
104
|
+
|
105
|
+
# Allows you to find an address by a string.
|
106
|
+
#
|
107
|
+
# Accepts a string with an address in any form and returns found addresses (up to 50 records).
|
108
|
+
# Building numbers should be specified without spaces: "building number""letter""building".
|
109
|
+
# The letter should be uppercase, and "building" (or "корп", "кор", "к") should be replaced with "/".
|
110
|
+
# Example: "город Минск улица Автодоровская 3Е корпус 4" should be transformed to "город Минск улица Автодоровская 3Е/4".
|
111
|
+
#
|
112
|
+
# @param address [String] The address string to search for.
|
113
|
+
# @return [Array<Hash>] An array of found addresses with postcode, region, city, street and other information.
|
114
|
+
# @raise [Belpost::ApiError] If the API returns an error response.
|
115
|
+
# @raise [Belpost::InvalidRequestError] If the address parameter is missing or has an incorrect format.
|
116
|
+
def find_address_by_string(address)
|
117
|
+
raise ValidationError, "Address must be filled" if address.nil?
|
118
|
+
raise ValidationError, "Address must be a string" unless address.is_a?(String)
|
119
|
+
raise ValidationError, "Address must be filled" if address.empty?
|
120
|
+
|
121
|
+
formatted_address = format_address(address)
|
122
|
+
response = @api_service.get(ApiPaths::GEO_DIRECTORY_SEARCH_ADDRESS, { search: formatted_address })
|
123
|
+
response.to_h
|
124
|
+
end
|
125
|
+
|
126
|
+
# Searches for postal codes by city, street, and building number.
|
127
|
+
#
|
128
|
+
# @param city [String] The city name (required)
|
129
|
+
# @param street [String] The street name (required)
|
130
|
+
# @param building [String] The building number (optional)
|
131
|
+
# @param limit [Integer] Maximum number of results (optional, default: 50, range: 1-200)
|
132
|
+
# @return [Array<Hash>] An array of found addresses with postcode, region, city, street and other information
|
133
|
+
# @raise [Belpost::ValidationError] If required parameters are missing or invalid
|
134
|
+
# @raise [Belpost::ApiError] If the API returns an error response
|
135
|
+
def search_postcode(city:, street:, building: nil, limit: 50)
|
136
|
+
raise ValidationError, "City must be filled" if city.nil?
|
137
|
+
raise ValidationError, "City must be a string" unless city.is_a?(String)
|
138
|
+
raise ValidationError, "City must be filled" if city.empty?
|
139
|
+
raise ValidationError, "Street must be filled" if street.nil?
|
140
|
+
raise ValidationError, "Street must be a string" unless street.is_a?(String)
|
141
|
+
raise ValidationError, "Street must be filled" if street.empty?
|
142
|
+
raise ValidationError, "Building must be a string" if building && !building.is_a?(String)
|
143
|
+
raise ValidationError, "Limit must be between 1 and 200" if limit < 1 || limit > 200
|
144
|
+
|
145
|
+
params = { city: city, street: street }
|
146
|
+
params[:building] = format_building_number(building) if building
|
147
|
+
params[:limit] = limit
|
148
|
+
|
149
|
+
response = @api_service.get(ApiPaths::GEO_DIRECTORY_POSTCODE, params)
|
150
|
+
response.to_h
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def format_address(address)
|
156
|
+
address.gsub(/\s+/, " ")
|
157
|
+
.gsub(/\s*корпус\s*(\d+)\s*/i, '/\1')
|
158
|
+
.gsub(/\s*корп\s*(\d+)\s*/i, '/\1')
|
159
|
+
.gsub(/\s*кор\s*(\d+)\s*/i, '/\1')
|
160
|
+
.gsub(/\s*к\s*(\d+)\s*/i, '/\1')
|
161
|
+
.strip
|
162
|
+
end
|
163
|
+
|
164
|
+
def format_building_number(building)
|
165
|
+
return building unless building
|
166
|
+
|
167
|
+
building.gsub(/\s+/, " ")
|
168
|
+
.gsub(/\s*корпус\s*(\d+)\s*/i, '/\1')
|
169
|
+
.gsub(/\s*корп\s*(\d+)\s*/i, '/\1')
|
170
|
+
.gsub(/\s*кор\s*(\d+)\s*/i, '/\1')
|
171
|
+
.gsub(/\s*к\s*(\d+)\s*/i, '/\1')
|
172
|
+
.strip
|
173
|
+
end
|
70
174
|
end
|
71
175
|
end
|
@@ -7,9 +7,32 @@ module Belpost
|
|
7
7
|
attr_accessor :base_url, :jwt_token, :timeout
|
8
8
|
|
9
9
|
def initialize
|
10
|
-
@base_url = ENV.fetch("BELPOST_API_URL")
|
10
|
+
@base_url = ENV.fetch("BELPOST_API_URL", "https://api.belpost.by")
|
11
11
|
@jwt_token = ENV.fetch("BELPOST_JWT_TOKEN", nil)
|
12
|
-
|
12
|
+
|
13
|
+
# Convert timeout to integer with a fallback to default
|
14
|
+
begin
|
15
|
+
@timeout = Integer(ENV.fetch("BELPOST_TIMEOUT", 10))
|
16
|
+
rescue ArgumentError
|
17
|
+
@timeout = 10
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Validates that all required configuration is present
|
22
|
+
# @raise [Belpost::ConfigurationError] If required configuration is missing
|
23
|
+
def validate!
|
24
|
+
raise ConfigurationError, "Base URL is required" if base_url.nil?
|
25
|
+
raise ConfigurationError, "JWT token is required" if jwt_token.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a hash representation of the configuration
|
29
|
+
# @return [Hash] The configuration as a hash
|
30
|
+
def to_h
|
31
|
+
{
|
32
|
+
base_url: base_url,
|
33
|
+
jwt_token: jwt_token,
|
34
|
+
timeout: timeout
|
35
|
+
}
|
13
36
|
end
|
14
37
|
end
|
15
38
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Belpost
|
4
|
+
module Models
|
5
|
+
# Model class for batch mailing
|
6
|
+
class Batch
|
7
|
+
attr_reader :postal_delivery_type, :direction, :payment_type, :negotiated_rate,
|
8
|
+
:name, :card_number, :postal_items_in_ops, :category, :is_document,
|
9
|
+
:is_declared_value, :is_partial_receipt
|
10
|
+
|
11
|
+
def initialize(data)
|
12
|
+
@postal_delivery_type = data[:postal_delivery_type]
|
13
|
+
@direction = data[:direction]
|
14
|
+
@payment_type = data[:payment_type]
|
15
|
+
@negotiated_rate = data[:negotiated_rate]
|
16
|
+
@name = data[:name]
|
17
|
+
@card_number = data[:card_number]
|
18
|
+
@postal_items_in_ops = data[:postal_items_in_ops]
|
19
|
+
@category = data[:category]
|
20
|
+
@is_document = data[:is_document]
|
21
|
+
@is_declared_value = data[:is_declared_value]
|
22
|
+
@is_partial_receipt = data[:is_partial_receipt]
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_h
|
26
|
+
{
|
27
|
+
postal_delivery_type: @postal_delivery_type,
|
28
|
+
direction: @direction,
|
29
|
+
payment_type: @payment_type,
|
30
|
+
negotiated_rate: @negotiated_rate,
|
31
|
+
name: @name,
|
32
|
+
card_number: @card_number,
|
33
|
+
postal_items_in_ops: @postal_items_in_ops,
|
34
|
+
category: @category,
|
35
|
+
is_document: @is_document,
|
36
|
+
is_declared_value: @is_declared_value,
|
37
|
+
is_partial_receipt: @is_partial_receipt
|
38
|
+
}.compact
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry-validation"
|
4
|
+
|
5
|
+
module Belpost
|
6
|
+
module Validation
|
7
|
+
# Schema for validating and formatting address strings
|
8
|
+
class AddressSchema < Dry::Validation::Contract
|
9
|
+
params do
|
10
|
+
required(:address).filled(:string)
|
11
|
+
end
|
12
|
+
|
13
|
+
rule(:address) do
|
14
|
+
# Remove extra spaces
|
15
|
+
address = value.gsub(/\s+/, " ").strip
|
16
|
+
|
17
|
+
# Replace building indicators with "/"
|
18
|
+
address = address.gsub(/\s+(корпус|корп|кор|к)\s+/, "/")
|
19
|
+
|
20
|
+
# Ensure building number format (no spaces between number, letter, and building)
|
21
|
+
address = address.gsub(/(\d+)\s*([А-Я])\s*(\d+)/, '\1\2/\3')
|
22
|
+
|
23
|
+
# Ensure letter is uppercase
|
24
|
+
address = address.gsub(/(\d+)([а-я])(\/\d+)/) { |m| "#{$1}#{$2.upcase}#{$3}" }
|
25
|
+
|
26
|
+
key.failure(address)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry-validation"
|
4
|
+
|
5
|
+
module Belpost
|
6
|
+
module Validation
|
7
|
+
# Schema for validating batch mailing data
|
8
|
+
class BatchSchema < Dry::Validation::Contract
|
9
|
+
params do
|
10
|
+
required(:postal_delivery_type).filled(:str?).value(
|
11
|
+
included_in?: %w[
|
12
|
+
ordered_small_package
|
13
|
+
letter_declare_value
|
14
|
+
package
|
15
|
+
ems
|
16
|
+
ordered_parcel_post
|
17
|
+
ordered_letter
|
18
|
+
ordered_postcard
|
19
|
+
small_package_declare_value
|
20
|
+
package_declare_value
|
21
|
+
ecommerce_economical
|
22
|
+
ecommerce_standard
|
23
|
+
ecommerce_elite
|
24
|
+
ecommerce_express
|
25
|
+
ecommerce_light
|
26
|
+
ecommerce_optima
|
27
|
+
]
|
28
|
+
)
|
29
|
+
|
30
|
+
required(:direction).filled(:str?).value(
|
31
|
+
included_in?: %w[internal CIS international]
|
32
|
+
)
|
33
|
+
|
34
|
+
required(:payment_type).filled(:str?).value(
|
35
|
+
included_in?: %w[
|
36
|
+
not_specified
|
37
|
+
cash
|
38
|
+
payment_order
|
39
|
+
electronic_personal_account
|
40
|
+
4
|
41
|
+
5
|
42
|
+
commitment_letter
|
43
|
+
]
|
44
|
+
)
|
45
|
+
|
46
|
+
required(:negotiated_rate).filled(:bool?)
|
47
|
+
|
48
|
+
optional(:name).maybe(:str?)
|
49
|
+
optional(:card_number).maybe(:str?)
|
50
|
+
optional(:postal_items_in_ops).maybe(:bool?)
|
51
|
+
optional(:category).maybe(:int?)
|
52
|
+
optional(:is_document).maybe(:bool?)
|
53
|
+
optional(:is_declared_value).maybe(:bool?)
|
54
|
+
optional(:is_partial_receipt).maybe(:bool?)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,154 +1,172 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dry
|
3
|
+
require "dry-validation"
|
4
4
|
|
5
5
|
module Belpost
|
6
6
|
# rubocop:disable Metrics/ModuleLength
|
7
7
|
module Validation
|
8
8
|
# Validation schema for parcel_data
|
9
9
|
# rubocop:disable Metrics/BlockLength
|
10
|
-
ParcelSchema
|
11
|
-
|
12
|
-
required(:
|
13
|
-
|
14
|
-
|
15
|
-
required(:
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
required(:
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
required(:
|
27
|
-
|
28
|
-
|
10
|
+
class ParcelSchema < Dry::Validation::Contract
|
11
|
+
params do
|
12
|
+
required(:parcel).hash do
|
13
|
+
required(:type).filled(:string, included_in?: %w[package small_package small_valued_package ems])
|
14
|
+
required(:attachment_type).filled(:string, included_in?: %w[products documents])
|
15
|
+
required(:measures).hash do
|
16
|
+
required(:weight).filled(:integer, gt?: 0)
|
17
|
+
optional(:long).value(:integer, gt?: 0)
|
18
|
+
optional(:width).value(:integer, gt?: 0)
|
19
|
+
optional(:height).value(:integer, gt?: 0)
|
20
|
+
end
|
21
|
+
required(:departure).hash do
|
22
|
+
required(:country).filled(:string, eql?: "BY")
|
23
|
+
required(:place).filled(:string, included_in?: %w[post_office])
|
24
|
+
optional(:place_uuid).maybe(:string)
|
25
|
+
end
|
26
|
+
required(:arrival).hash do
|
27
|
+
required(:country).filled(:string)
|
28
|
+
required(:place).filled(:string, included_in?: %w[post_office])
|
29
|
+
optional(:place_uuid).maybe(:string)
|
30
|
+
end
|
31
|
+
optional(:s10code).maybe(:string)
|
29
32
|
end
|
30
|
-
optional(:s10code).maybe(:string)
|
31
|
-
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
34
|
+
optional(:addons).hash do
|
35
|
+
optional(:cash_on_delivery).maybe(:hash) do
|
36
|
+
required(:currency).filled(:string, eql?: "BYN")
|
37
|
+
required(:value).filled(:float, gt?: 0)
|
38
|
+
end
|
39
|
+
optional(:declared_value).maybe(:hash) do
|
40
|
+
required(:currency).filled(:string, eql?: "BYN")
|
41
|
+
required(:value).filled(:float, gt?: 0)
|
42
|
+
end
|
43
|
+
optional(:IOSS).maybe(:string)
|
44
|
+
optional(:registered_notification).maybe(:string)
|
45
|
+
optional(:simple_notification).maybe(:bool)
|
46
|
+
optional(:sms_notification).maybe(:bool)
|
47
|
+
optional(:email_notification).maybe(:bool)
|
48
|
+
optional(:priority_parcel).maybe(:bool)
|
49
|
+
optional(:attachment_inventory).maybe(:bool)
|
50
|
+
optional(:paid_shipping).maybe(:bool)
|
51
|
+
optional(:careful_fragile).maybe(:bool)
|
52
|
+
optional(:bulky).maybe(:bool)
|
53
|
+
optional(:ponderous).maybe(:bool)
|
54
|
+
optional(:payment_upon_receipt).maybe(:bool)
|
55
|
+
optional(:hand_over_personally).maybe(:bool)
|
56
|
+
optional(:return_of_documents).maybe(:bool)
|
57
|
+
optional(:open_upon_delivery).maybe(:bool)
|
58
|
+
optional(:delivery_to_work).maybe(:bool)
|
59
|
+
optional(:time_of_delivery).maybe(:hash) do
|
60
|
+
required(:type).filled(:string, included_in?: %w[level1 level2 level3 level4])
|
61
|
+
optional(:time_interval).hash do
|
62
|
+
required(:from).filled(:string)
|
63
|
+
required(:to).filled(:string)
|
64
|
+
end
|
63
65
|
end
|
64
66
|
end
|
65
|
-
end
|
66
67
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
required(:region).filled(:string)
|
79
|
-
required(:district).filled(:string)
|
80
|
-
required(:locality).hash do
|
81
|
-
required(:type).filled(:string)
|
82
|
-
required(:name).filled(:string)
|
68
|
+
optional(:sender).hash do
|
69
|
+
required(:type).filled(:string, included_in?: %w[legal_person natural_person])
|
70
|
+
required(:info).hash do
|
71
|
+
optional(:organization_name).maybe(:string)
|
72
|
+
optional(:taxpayer_number).maybe(:string)
|
73
|
+
optional(:IBAN).maybe(:string)
|
74
|
+
optional(:BIC).maybe(:string)
|
75
|
+
optional(:bank).maybe(:string)
|
76
|
+
optional(:first_name).maybe(:string)
|
77
|
+
optional(:second_name).maybe(:string)
|
78
|
+
optional(:last_name).maybe(:string)
|
83
79
|
end
|
84
|
-
required(:
|
85
|
-
required(:
|
86
|
-
required(:
|
80
|
+
required(:location).hash do
|
81
|
+
required(:code).filled(:string)
|
82
|
+
required(:region).filled(:string)
|
83
|
+
required(:district).filled(:string)
|
84
|
+
required(:locality).hash do
|
85
|
+
required(:type).filled(:string)
|
86
|
+
required(:name).filled(:string)
|
87
|
+
end
|
88
|
+
required(:road).hash do
|
89
|
+
required(:type).filled(:string)
|
90
|
+
required(:name).filled(:string)
|
91
|
+
end
|
92
|
+
required(:building).filled(:string)
|
93
|
+
optional(:housing).maybe(:string)
|
94
|
+
optional(:apartment).maybe(:string)
|
87
95
|
end
|
88
|
-
|
89
|
-
optional(:
|
90
|
-
optional(:apartment).maybe(:string)
|
96
|
+
optional(:email).maybe(:string)
|
97
|
+
optional(:phone).maybe(:string)
|
91
98
|
end
|
92
|
-
required(:email).filled(:string)
|
93
|
-
required(:phone).filled(:string)
|
94
|
-
end
|
95
99
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
optional(:district).maybe(:string)
|
108
|
-
optional(:locality).maybe(:hash) do
|
109
|
-
optional(:type).maybe(:string)
|
110
|
-
optional(:name).maybe(:string)
|
100
|
+
optional(:recipient).hash do
|
101
|
+
required(:type).filled(:string, included_in?: %w[legal_person natural_person])
|
102
|
+
required(:info).hash do
|
103
|
+
optional(:organization_name).maybe(:string)
|
104
|
+
optional(:taxpayer_number).maybe(:string)
|
105
|
+
optional(:IBAN).maybe(:string)
|
106
|
+
optional(:BIC).maybe(:string)
|
107
|
+
optional(:bank).maybe(:string)
|
108
|
+
optional(:first_name).maybe(:string)
|
109
|
+
optional(:second_name).maybe(:string)
|
110
|
+
optional(:last_name).maybe(:string)
|
111
111
|
end
|
112
|
-
|
113
|
-
|
114
|
-
|
112
|
+
required(:location).hash do
|
113
|
+
required(:code).filled(:string)
|
114
|
+
required(:region).filled(:string)
|
115
|
+
required(:district).filled(:string)
|
116
|
+
required(:locality).hash do
|
117
|
+
required(:type).filled(:string)
|
118
|
+
required(:name).filled(:string)
|
119
|
+
end
|
120
|
+
required(:road).hash do
|
121
|
+
required(:type).filled(:string)
|
122
|
+
required(:name).filled(:string)
|
123
|
+
end
|
124
|
+
required(:building).filled(:string)
|
125
|
+
optional(:housing).maybe(:string)
|
126
|
+
optional(:apartment).maybe(:string)
|
115
127
|
end
|
116
|
-
optional(:
|
117
|
-
optional(:
|
118
|
-
optional(:apartment).maybe(:string)
|
119
|
-
optional(:address).maybe(:string)
|
128
|
+
optional(:email).maybe(:string)
|
129
|
+
optional(:phone).maybe(:string)
|
120
130
|
end
|
121
|
-
optional(:email).maybe(:string)
|
122
|
-
required(:phone).filled(:string)
|
123
|
-
end
|
124
131
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
required(:local).filled(:string)
|
129
|
-
required(:unit).hash do
|
132
|
+
optional(:cp72).hash do
|
133
|
+
optional(:items).array(:hash) do
|
134
|
+
required(:name).filled(:string)
|
130
135
|
required(:local).filled(:string)
|
131
|
-
required(:
|
136
|
+
required(:unit).hash do
|
137
|
+
required(:local).filled(:string)
|
138
|
+
required(:en).filled(:string)
|
139
|
+
end
|
140
|
+
required(:count).filled(:integer, gt?: 0)
|
141
|
+
required(:weight).filled(:integer, gt?: 0)
|
142
|
+
required(:price).hash do
|
143
|
+
required(:currency).filled(:string)
|
144
|
+
required(:value).filled(:float, gt?: 0)
|
145
|
+
end
|
146
|
+
optional(:code).maybe(:string)
|
147
|
+
optional(:country).maybe(:string)
|
132
148
|
end
|
133
|
-
|
134
|
-
required(:weight).filled(:integer, gt?: 0)
|
135
|
-
required(:price).hash do
|
149
|
+
optional(:price).hash do
|
136
150
|
required(:currency).filled(:string)
|
137
151
|
required(:value).filled(:float, gt?: 0)
|
138
152
|
end
|
139
|
-
optional(:
|
140
|
-
optional(:
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
153
|
+
optional(:category).filled(:string, included_in?: %w[gift documents sample returned_goods merchandise other])
|
154
|
+
optional(:explanation).maybe(:string)
|
155
|
+
optional(:comments).maybe(:string)
|
156
|
+
optional(:invoice).maybe(:string)
|
157
|
+
optional(:licences).array(:string)
|
158
|
+
optional(:certificates).array(:string)
|
145
159
|
end
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
160
|
+
end
|
161
|
+
|
162
|
+
# Add class method to make it compatible with the tests
|
163
|
+
def self.call(params)
|
164
|
+
new.call(params)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Add validation rule for organization_name when sender type is legal_person
|
168
|
+
rule('sender.info.organization_name') do
|
169
|
+
key.failure('must be filled') if values[:sender] && values[:sender][:type] == 'legal_person' && !values.dig(:sender, :info, :organization_name)
|
152
170
|
end
|
153
171
|
end
|
154
172
|
# rubocop:enable Metrics/BlockLength
|
data/lib/belpost/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: belpost
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- KuberLite
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: dotenv
|
@@ -37,6 +37,20 @@ dependencies:
|
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '1.0'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: dry-schema
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.0'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.0'
|
40
54
|
description: Gem for working with the 'Belpost' delivery service via API
|
41
55
|
email:
|
42
56
|
- kuberlite@gmail.com
|
@@ -55,15 +69,19 @@ files:
|
|
55
69
|
- Rakefile
|
56
70
|
- belpost.gemspec
|
57
71
|
- lib/belpost.rb
|
72
|
+
- lib/belpost/api_paths.rb
|
58
73
|
- lib/belpost/api_service.rb
|
59
74
|
- lib/belpost/client.rb
|
60
75
|
- lib/belpost/configuration.rb
|
61
76
|
- lib/belpost/errors.rb
|
62
77
|
- lib/belpost/models/api_response.rb
|
78
|
+
- lib/belpost/models/batch.rb
|
63
79
|
- lib/belpost/models/customs_declaration.rb
|
64
80
|
- lib/belpost/models/parcel.rb
|
65
81
|
- lib/belpost/models/parcel_builder.rb
|
66
82
|
- lib/belpost/retry.rb
|
83
|
+
- lib/belpost/validations/address_schema.rb
|
84
|
+
- lib/belpost/validations/batch_schema.rb
|
67
85
|
- lib/belpost/validations/parcel_schema.rb
|
68
86
|
- lib/belpost/version.rb
|
69
87
|
homepage: https://github.com/KuberLite/belpost
|
@@ -89,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
107
|
- !ruby/object:Gem::Version
|
90
108
|
version: '0'
|
91
109
|
requirements: []
|
92
|
-
rubygems_version: 3.6.
|
110
|
+
rubygems_version: 3.6.7
|
93
111
|
specification_version: 4
|
94
112
|
summary: Belpost API wrapper
|
95
113
|
test_files: []
|