cdek_api_client 0.1.0 → 0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 389563fd9ba0f235cdc75afdc77906d9e2fb7d3f6da3d4392105758c8ad8756a
4
- data.tar.gz: dfa1b6d50ea42547dfdf8c5846a47c9882e8b2ab5f56557b014d122a026c5eb2
3
+ metadata.gz: fb260a05ab2e01a502a9170810e6f4ad293f4250d369aa78495346ee91b41f42
4
+ data.tar.gz: 1072390e4220defd519199194b301a166caade65276204ceec4314d98e738562
5
5
  SHA512:
6
- metadata.gz: 364b5510d3f833a43ff3ab1d0581844821e1cbce1211a61b81802c3fb1f228d901621552c57e4052aaa88ae6609861ee5a2e1ff6ad759eaa970d51b70de1b3a5
7
- data.tar.gz: b982eef2e9d6bb5f268204af574605f7f96a077331cfeb38d58db02a2ef9be601e5cac83439b4aa879b245ac41262c97a3dcb6cc83eca2bf977e5359af989089
6
+ metadata.gz: d1bdbca95336d4c39bb72909e880aa8473b2a0249ccc997a504916c55944b8fe750454e1c5bd171eacfe45c47f9dc3a3b92743957a898102c39d90c8ff88ef7a
7
+ data.tar.gz: e0f39d6d3ccb456f98446974e96c1160a001fc6c9970fc9e2162efcc24cdd78aa003e2516d6256ce4de9add37634c83b3d9c7e7a125bc34fbd9a668c9647591f
data/README.md CHANGED
@@ -2,12 +2,24 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/cdek_api_client.svg)](https://badge.fury.io/rb/cdek_api_client)
4
4
 
5
- A Ruby client for interacting with the CDEK API, providing functionalities for order creation, tracking, tariff calculation, location data retrieval, and webhook management. This gem ensures clean, robust, and maintainable code with proper validations.
5
+ ### Other Languages
6
6
 
7
- This Readme is also available in:
7
+ - [Русский](README_RUS.md)
8
+ - [Татарча](README_TAT.md)
9
+ - [English](README.md)
8
10
 
9
- - [Russian](README_RUS.md)
10
- - [Tatar](README_TAT.md)
11
+ **Important:** This gem is in the early stages of development and it is shared as it is. Any support for development or feedback is welcome; please check the [Contributing](#contributing) section for more information.
12
+
13
+ ## Overview
14
+
15
+ CDEK ([СДЭК](https://www.cdek.ru/)) is a big logistics company in Russia, that provides a wide range of delivery services for businesses and individuals. The [CDEK API](https://www.cdek.ru/ru/integration/api) allows developers to integrate CDEK's services into their applications, enabling functionalities such as order creation, tracking, tariff calculation, location data retrieval, and webhook management.
16
+
17
+ The `cdek_api_client` gem offers a clean and robust interface to interact with the CDEK API, ensuring maintainable code with proper validations. This gem supports the following features:
18
+
19
+ - Creating and tracking orders
20
+ - Calculating tariffs
21
+ - Retrieving location data (cities, regions, postal codes, and offices)
22
+ - Managing webhooks
11
23
 
12
24
  ## Table of Contents
13
25
 
@@ -19,12 +31,15 @@ This Readme is also available in:
19
31
  - [Calculating Tariff](#calculating-tariff)
20
32
  - [Getting Location Data](#getting-location-data)
21
33
  - [Setting Up Webhooks](#setting-up-webhooks)
34
+ - [Fetching and Saving Location Data](#fetching-and-saving-location-data)
22
35
  - [Entities](#entities)
23
36
  - [OrderData](#orderdata)
24
37
  - [Recipient](#recipient)
25
38
  - [Sender](#sender)
26
39
  - [Package](#package)
27
40
  - [Item](#item)
41
+ - [TODO List](#todo-list)
42
+ - [Changelog](#changelog)
28
43
  - [Contributing](#contributing)
29
44
  - [License](#license)
30
45
 
@@ -36,8 +51,6 @@ Add this line to your application's Gemfile:
36
51
  gem 'cdek_api_client'
37
52
  ```
38
53
 
39
- ````
40
-
41
54
  And then execute:
42
55
 
43
56
  ```sh
@@ -222,7 +235,44 @@ rescue => e
222
235
  end
223
236
  ```
224
237
 
225
- ## Entities
238
+ ### Fetching Location Data
239
+
240
+ The gem has pre-cached values and uses them by default. Users can override this behavior by fetching live data.
241
+
242
+ You can fetch cities, regions, offices, and postal code data directly from CDEK API.
243
+
244
+ ```ruby
245
+
246
+ # Fetching cities
247
+ begin
248
+ cities = location_client.cities(use_live_data: true)
249
+ rescue => e
250
+ puts "Error fetching cities: #{e.message}"
251
+ end
252
+
253
+ # Fetching regions
254
+ begin
255
+ regions = location_client.regions(use_live_data: true)
256
+ rescue => e
257
+ puts "Error fetching regions: #{e.message}"
258
+ end
259
+
260
+ # Fetching offices
261
+ begin
262
+ offices = location_client.offices(use_live_data: true)
263
+ rescue => e
264
+ puts "Error fetching offices: #{e.message}"
265
+ end
266
+
267
+ # Fetching postal codes for each city
268
+ begin
269
+ cities = location_client.cities(use_live_data: true)
270
+ rescue => e
271
+ puts "Error fetching postal codes: #{e.message}"
272
+ end
273
+ ```
274
+
275
+ ### Entities
226
276
 
227
277
  ### OrderData
228
278
 
@@ -237,7 +287,7 @@ Attributes:
237
287
  - `recipient` (Recipient, required): The recipient details.
238
288
  - `sender` (Sender, required): The sender details.
239
289
  - `from_location` (Hash, required): The location details from where the order is shipped.
240
- - `to_location` (Hash, required): The location details to where the order is shipped.
290
+ - `to_location` (Hash, required): The location details of where the order is shipped.
241
291
  - `services` (Array): Additional services.
242
292
  - `packages` (Array, required): List of packages.
243
293
 
@@ -253,7 +303,7 @@ Attributes:
253
303
 
254
304
  ### Sender
255
305
 
256
- Represents the sender details.
306
+ Represents the sender's details.
257
307
 
258
308
  Attributes:
259
309
 
@@ -290,17 +340,25 @@ Attributes:
290
340
 
291
341
  ## TODO List
292
342
 
293
- - [ ] Restructure the codebase for better organization.
294
- - [ ] Add mappings for CDEK internal codes.
343
+ - [x] Restructure the codebase for better organization.
344
+ - [x] Add mappings for CDEK internal codes.
295
345
  - [ ] Add more API endpoints and data entities.
296
346
  - [ ] Check all attributes for required and optional fields.
297
347
  - [ ] Add documentation for all classes and methods.
298
348
 
349
+ ## Changelog
350
+
351
+ ### v0.2.0
352
+
353
+ - **Added**: Improved error handling and response parsing in `Client`.
354
+ - **Updated**: Code structure for better organization.
355
+ - **Updated**: Specs for `Client` and `API` classes.
356
+ - **Updated**: `README.md` with detailed usage examples, including fetching and saving location data with optional live data fetching.
357
+
299
358
  ## Contributing
300
359
 
301
- Bug reports and pull requests are welcome on GitHub at [https://github.com/your-username/cdek_api_client](https://github.com/your-username/cdek_api_client).
360
+ Bug reports and pull requests are welcome on GitHub. This gem is used in a couple of projects and fulfills the requirements of those projects. If you have any suggestions or improvements, feel free to open an issue or a pull request.
302
361
 
303
362
  ## License
304
363
 
305
- The gem is available as open-source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
306
- ````
364
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module CDEKApiClient
6
+ module API
7
+ # Handles location-related API requests.
8
+ class Location
9
+ # Initializes the Location object.
10
+ #
11
+ # @param client [CDEKApiClient::Client] the client instance.
12
+ def initialize(client)
13
+ @client = client
14
+ end
15
+
16
+ # Retrieves a list of cities.
17
+ #
18
+ # @param use_live_data [Boolean] whether to use live data or cached data.
19
+ # @return [Array<Hash>] list of cities.
20
+ def cities(use_live_data: false)
21
+ use_live_data ? @client.request('get', 'location/cities') : read_data_from_file('cities_mapping.json')
22
+ end
23
+
24
+ # Retrieves a list of regions.
25
+ #
26
+ # @param use_live_data [Boolean] whether to use live data or cached data.
27
+ # @return [Array<Hash>] list of regions.
28
+ def regions(use_live_data: false)
29
+ use_live_data ? @client.request('get', 'location/regions') : read_data_from_file('regions_mapping.json')
30
+ end
31
+
32
+ # Retrieves a list of offices.
33
+ #
34
+ # @param use_live_data [Boolean] whether to use live data or cached data.
35
+ # @return [Array<Hash>] list of offices.
36
+ def offices(use_live_data: false)
37
+ use_live_data ? @client.request('get', 'deliverypoints') : read_data_from_file('offices_mapping.json')
38
+ end
39
+
40
+ # Retrieves a list of postal codes.
41
+ #
42
+ # @param city_code [String, nil] the city code to filter postal codes.
43
+ # @param use_live_data [Boolean] whether to use live data or cached data.
44
+ # @return [Array<Hash>] list of postal codes.
45
+ def postal_codes(city_code = nil, use_live_data: false)
46
+ if use_live_data
47
+ if city_code
48
+ @client.request('get',
49
+ "location/postalcodes?code=#{city_code}")
50
+ else
51
+ @client.request('get',
52
+ 'location/postalcodes')
53
+ end
54
+ else
55
+ read_data_from_file('postal_codes_mapping.json')
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ # Reads data from a file.
62
+ #
63
+ # @param filename [String] the name of the file to read.
64
+ # @return [Hash] the parsed JSON data from the file.
65
+ def read_data_from_file(filename)
66
+ file_path = File.join('data', filename)
67
+ JSON.parse(File.read(file_path))
68
+ rescue StandardError => e
69
+ @client.logger.error("Failed to read data from file: #{e.message}")
70
+ { 'error' => e.message }
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CDEKApiClient
4
+ module API
5
+ # Handles order-related API requests.
6
+ class Order
7
+ # Initializes the Order object.
8
+ #
9
+ # @param client [CDEKApiClient::Client] the client instance.
10
+ def initialize(client)
11
+ @client = client
12
+ end
13
+
14
+ # Creates a new order.
15
+ #
16
+ # @param order_data [CDEKApiClient::Entities::OrderData] the data for the order.
17
+ # @return [Hash] the response from the API.
18
+ def create(order_data)
19
+ response = @client.request('post', 'orders', body: order_data)
20
+ handle_response(response)
21
+ end
22
+
23
+ # Tracks an order by its UUID.
24
+ #
25
+ # @param order_uuid [String] the UUID of the order.
26
+ # @return [Hash] the tracking information.
27
+ def track(order_uuid)
28
+ response = @client.request('get', "orders/#{order_uuid}")
29
+ handle_response(response)
30
+ end
31
+
32
+ private
33
+
34
+ # Handles the response from the API.
35
+ #
36
+ # @param response [Net::HTTPResponse] the response from the API.
37
+ # @return [Hash] the parsed response.
38
+ def handle_response(response)
39
+ @client.send(:handle_response, response)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CDEKApiClient
4
+ module API
5
+ # Handles tariff-related API requests.
6
+ class Tariff
7
+ # Initializes the Tariff object.
8
+ #
9
+ # @param client [CDEKApiClient::Client] the client instance.
10
+ def initialize(client)
11
+ @client = client
12
+ end
13
+
14
+ # Calculates the tariff.
15
+ #
16
+ # @param tariff_data [CDEKApiClient::Entities::TariffData] the data for the tariff calculation.
17
+ # @return [Hash] the response from the API.
18
+ def calculate(tariff_data)
19
+ @client.request('post', 'calculator/tariff', body: tariff_data)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CDEKApiClient
4
+ module API
5
+ # Handles order tracking requests to the CDEK API.
6
+ class TrackOrder
7
+ BASE_URL = ENV.fetch('CDEK_API_URL', 'https://api.edu.cdek.ru/v2')
8
+ TRACK_ORDER_URL = "#{BASE_URL}/orders/%<uuid>s".freeze
9
+
10
+ # Initializes the TrackOrder object.
11
+ #
12
+ # @param client [CDEKApiClient::Client] the client instance.
13
+ def initialize(client)
14
+ @client = client
15
+ end
16
+
17
+ # Retrieves tracking information for an order.
18
+ #
19
+ # @param order_uuid [String] the UUID of the order.
20
+ # @return [Hash] the tracking information.
21
+ # @raise [ArgumentError] if the UUID is invalid.
22
+ def get(order_uuid)
23
+ validate_uuid(order_uuid)
24
+
25
+ response = @client.auth_connection.get(format(TRACK_ORDER_URL, uuid: order_uuid))
26
+ handle_response(response)
27
+ end
28
+
29
+ private
30
+
31
+ # Validates the order UUID.
32
+ #
33
+ # @param uuid [String] the UUID to validate.
34
+ # @raise [ArgumentError] if the UUID is invalid.
35
+ def validate_uuid(uuid)
36
+ @client.send(:validate_uuid, uuid)
37
+ end
38
+
39
+ # Handles the response from the API.
40
+ #
41
+ # @param response [Net::HTTPResponse] the response from the API.
42
+ # @return [Hash] the parsed response.
43
+ def handle_response(response)
44
+ @client.send(:handle_response, response)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CDEKApiClient
4
+ module API
5
+ # Handles webhook-related API requests.
6
+ class Webhook
7
+ # Initializes the Webhook object.
8
+ #
9
+ # @param client [CDEKApiClient::Client] the client instance.
10
+ def initialize(client)
11
+ @client = client
12
+ end
13
+
14
+ # Registers a new webhook.
15
+ #
16
+ # @param webhook_data [CDEKApiClient::Entities::Webhook] the data for the webhook.
17
+ # @return [Hash] the response from the API.
18
+ def register(webhook_data)
19
+ response = @client.request('post', 'webhooks', body: webhook_data)
20
+ @client.send(:handle_response, response)
21
+ end
22
+
23
+ # Retrieves a list of registered webhooks.
24
+ #
25
+ # @return [Array<Hash>] the list of webhooks.
26
+ def list
27
+ response = @client.request('get', 'webhooks')
28
+ @client.send(:handle_response, response)
29
+ end
30
+
31
+ # Deletes a webhook by its ID.
32
+ #
33
+ # @param webhook_id [String] the ID of the webhook to delete.
34
+ # @return [Hash] the response from the API.
35
+ def delete(webhook_id)
36
+ response = @client.request('delete', "webhooks/#{webhook_id}")
37
+ @client.send(:handle_response, response)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,114 +1,141 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'faraday'
4
- require 'faraday_middleware'
3
+ require 'net/http'
4
+ require 'uri'
5
5
  require 'json'
6
6
  require 'logger'
7
+ require_relative 'api/location'
8
+ require_relative 'api/order'
9
+ require_relative 'api/tariff'
10
+ require_relative 'api/webhook'
7
11
 
8
12
  module CDEKApiClient
9
- ##
10
13
  # Client class for interacting with the CDEK API.
11
- #
12
- # This class provides methods for authentication and initializing the API resources
13
- # for orders, locations, tariffs, and webhooks.
14
- #
15
- # @attr_reader [String] token The access token used for authentication.
16
- # @attr_reader [Logger] logger The logger used for logging HTTP requests and responses.
17
- # @attr_reader [Order] order The Order resource for interacting with order-related API endpoints.
18
- # @attr_reader [Location] location The Location resource for interacting with location-related API endpoints.
19
- # @attr_reader [Tariff] tariff The Tariff resource for interacting with tariff-related API endpoints.
20
- # @attr_reader [Webhook] webhook The Webhook resource for interacting with webhook-related API endpoints.
21
14
  class Client
22
15
  BASE_URL = ENV.fetch('CDEK_API_URL', 'https://api.edu.cdek.ru/v2')
23
16
  TOKEN_URL = "#{BASE_URL}/oauth/token".freeze
24
17
 
25
- attr_reader :token, :logger, :order, :location, :tariff, :webhook
18
+ # @return [String] the access token for API authentication.
19
+ attr_reader :token
20
+ # @return [Logger] the logger instance.
21
+ attr_reader :logger
22
+ # @return [CDEKApiClient::Order] the order API interface.
23
+ attr_reader :order
24
+ # @return [CDEKApiClient::Location] the location API interface.
25
+ attr_reader :location
26
+ # @return [CDEKApiClient::Tariff] the tariff API interface.
27
+ attr_reader :tariff
28
+ # @return [CDEKApiClient::Webhook] the webhook API interface.
29
+ attr_reader :webhook
26
30
 
27
- ##
28
- # Initializes a new Client object.
31
+ # Initializes the client with API credentials and logger.
29
32
  #
30
- # @param [String] client_id The client ID for authentication.
31
- # @param [String] client_secret The client secret for authentication.
32
- # @param [Logger] logger The logger for logging HTTP requests and responses.
33
+ # @param client_id [String] the client ID.
34
+ # @param client_secret [String] the client secret.
35
+ # @param logger [Logger] the logger instance.
33
36
  def initialize(client_id, client_secret, logger: Logger.new($stdout))
34
37
  @client_id = client_id
35
38
  @client_secret = client_secret
36
39
  @logger = logger
37
40
  @token = authenticate
38
41
 
39
- @order = CDEKApiClient::Order.new(self)
40
- @location = CDEKApiClient::Location.new(self)
41
- @tariff = CDEKApiClient::Tariff.new(self)
42
- @webhook = CDEKApiClient::Webhook.new(self)
42
+ @order = CDEKApiClient::API::Order.new(self)
43
+ @location = CDEKApiClient::API::Location.new(self)
44
+ @tariff = CDEKApiClient::API::Tariff.new(self)
45
+ @webhook = CDEKApiClient::API::Webhook.new(self)
43
46
  end
44
47
 
45
- ##
46
- # Authenticates with the CDEK API and retrieves an access token.
48
+ # Authenticates with the API and retrieves an access token.
47
49
  #
48
- # @return [String] The access token.
49
- # @raise [Error] if there is an error getting the token.
50
+ # @return [String] the access token.
51
+ # @raise [StandardError] if authentication fails.
50
52
  def authenticate
51
- response = connection.post(TOKEN_URL) do |req|
52
- req.body = {
53
- grant_type: 'client_credentials',
54
- client_id: @client_id,
55
- client_secret: @client_secret
56
- }
57
- end
53
+ uri = URI(TOKEN_URL)
54
+ response = Net::HTTP.post_form(uri, {
55
+ grant_type: 'client_credentials',
56
+ client_id: @client_id,
57
+ client_secret: @client_secret
58
+ })
58
59
 
59
- raise Error, "Error getting token: #{response.body}" unless response.success?
60
+ raise "Error getting token: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
60
61
 
61
- response.body['access_token']
62
+ JSON.parse(response.body)['access_token']
62
63
  end
63
64
 
64
- ##
65
- # Creates a Faraday connection object.
65
+ # Makes an HTTP request to the API.
66
66
  #
67
- # @return [Faraday::Connection] The Faraday connection object.
68
- def connection
69
- Faraday.new(url: BASE_URL) do |conn|
70
- conn.request :url_encoded
71
- conn.response :json, content_type: /\bjson$/
72
- conn.adapter Faraday.default_adapter
73
- conn.response :logger, @logger, bodies: true
74
- end
67
+ # @param method [String] the HTTP method (e.g., 'get', 'post').
68
+ # @param path [String] the API endpoint path.
69
+ # @param body [Hash, nil] the request body.
70
+ # @return [Hash, Array] the parsed response.
71
+ def request(method, path, body: nil)
72
+ uri = URI("#{BASE_URL}/#{path}")
73
+ http = Net::HTTP.new(uri.host, uri.port)
74
+ http.use_ssl = true
75
+ request = build_request(method, uri, body)
76
+ response = http.request(request)
77
+ handle_response(response)
78
+ rescue StandardError => e
79
+ @logger.error("HTTP request failed: #{e.message}")
80
+ { 'error' => e.message }
75
81
  end
76
82
 
77
- ##
78
- # Creates a Faraday connection object with authorization.
83
+ private
84
+
85
+ # Builds an HTTP request with the specified method, URI, and body.
79
86
  #
80
- # @return [Faraday::Connection] The Faraday connection object with authorization.
81
- def auth_connection
82
- Faraday.new(url: BASE_URL) do |conn|
83
- conn.request :url_encoded
84
- conn.response :json, content_type: /\bjson$/
85
- conn.authorization :Bearer, @token
86
- conn.adapter Faraday.default_adapter
87
- conn.response :logger, @logger, bodies: true
88
- end
87
+ # @param method [String] the HTTP method (e.g., 'get', 'post').
88
+ # @param uri [URI::HTTP] the URI for the request.
89
+ # @param body [Hash, nil] the request body.
90
+ # @return [Net::HTTPRequest] the constructed HTTP request.
91
+ def build_request(method, uri, body)
92
+ request_class = Net::HTTP.const_get(method.capitalize)
93
+ request = request_class.new(uri.request_uri)
94
+ request['Authorization'] = "Bearer #{@token}"
95
+ request['Content-Type'] = 'application/json'
96
+ request.body = body.to_json if body
97
+ request
89
98
  end
90
99
 
91
- ##
92
- # Handles the response from the API.
100
+ # Handles the API response, parsing JSON and handling errors.
93
101
  #
94
- # @param [Faraday::Response] response The response object.
95
- # @return [Hash] The parsed response body.
96
- # @raise [Error] if the response is not successful.
102
+ # @param response [Net::HTTPResponse] the HTTP response.
103
+ # @return [Hash, Array] the parsed response.
97
104
  def handle_response(response)
98
- raise Error, "Error: #{response.body}" unless response.success?
105
+ case response
106
+ when Net::HTTPSuccess
107
+ parsed_response = parse_json(response.body)
108
+ return parsed_response unless parsed_response.is_a?(Hash) && parsed_response.key?('error')
99
109
 
100
- response.body
110
+ log_error("API Error: #{parsed_response['error']}")
111
+ { 'error' => parsed_response['error'] }
112
+ when Array, Hash
113
+ response
114
+ else
115
+ log_error("Unexpected response type: #{response.class}")
116
+ { 'error' => "Unexpected response type: #{response.class}" }
117
+ end
118
+ rescue JSON::ParserError => e
119
+ log_error("Failed to parse response: #{e.message}")
120
+ { 'error' => "Failed to parse response: #{e.message}" }
101
121
  end
102
122
 
103
- ##
104
- # Validates the format of a UUID.
123
+ # Parses a JSON string, handling any parsing errors.
105
124
  #
106
- # @param [String] uuid The UUID to validate.
107
- # @raise [RuntimeError] if the UUID format is invalid.
108
- def validate_uuid(uuid)
109
- return if uuid.match?(/\A[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}\z/)
125
+ # @param body [String] the JSON string to parse.
126
+ # @return [Hash] the parsed JSON.
127
+ def parse_json(body)
128
+ JSON.parse(body)
129
+ rescue JSON::ParserError => e
130
+ log_error("Failed to parse JSON body: #{e.message}")
131
+ { 'error' => "Failed to parse JSON body: #{e.message}" }
132
+ end
110
133
 
111
- raise 'Invalid UUID format'
134
+ # Logs an error message.
135
+ #
136
+ # @param message [String] the error message to log.
137
+ def log_error(message)
138
+ @logger.error(message)
112
139
  end
113
140
  end
114
141
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module CDEKApiClient
4
4
  module Entities
5
+ # CurrencyMapper is a utility module that maps currency codes to their respective integer representations.
5
6
  module CurrencyMapper
6
7
  CURRENCY_CODES = {
7
8
  'RUB' => 1,
@@ -26,6 +27,11 @@ module CDEKApiClient
26
27
  'JPY' => 55
27
28
  }.freeze
28
29
 
30
+ # Converts a currency code to its corresponding integer representation.
31
+ #
32
+ # @param currency [String] the currency code to convert.
33
+ # @return [Integer] the integer representation of the currency code.
34
+ # @raise [ArgumentError] if the currency code is invalid.
29
35
  def self.to_code(currency)
30
36
  CURRENCY_CODES[currency] || (raise ArgumentError, "Invalid currency code: #{currency}")
31
37
  end
@@ -5,6 +5,8 @@ require_relative 'payment'
5
5
 
6
6
  module CDEKApiClient
7
7
  module Entities
8
+ # Represents an item in the CDEK API.
9
+ # Each item has attributes such as ware key, payment, name, cost, amount, weight, and optional URL.
8
10
  class Item
9
11
  include Validatable
10
12
 
@@ -17,6 +19,16 @@ module CDEKApiClient
17
19
  validates :amount, type: :integer, presence: true
18
20
  validates :weight, type: :integer, presence: true
19
21
 
22
+ # Initializes a new Item object.
23
+ #
24
+ # @param ware_key [String] the ware key of the item.
25
+ # @param payment [Payment] the payment details of the item.
26
+ # @param name [String] the name of the item.
27
+ # @param cost [Integer] the cost of the item.
28
+ # @param amount [Integer] the amount of the item.
29
+ # @param weight [Integer] the weight of the item.
30
+ # @param url [String, nil] the optional URL of the item.
31
+ # @raise [ArgumentError] if any attribute validation fails.
20
32
  def initialize(ware_key:, payment:, name:, cost:, amount:, weight:, url: nil)
21
33
  @ware_key = ware_key
22
34
  @payment = payment
@@ -28,6 +40,9 @@ module CDEKApiClient
28
40
  validate!
29
41
  end
30
42
 
43
+ # Converts the Item object to a JSON representation.
44
+ #
45
+ # @return [String] the JSON representation of the Item.
31
46
  def to_json(*_args)
32
47
  {
33
48
  ware_key: @ware_key,