cdek_client 0.0.1

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,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cdek_client/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cdek_client'
8
+ spec.version = CdekClient::VERSION
9
+ spec.authors = ['Babur Usenakunov']
10
+ spec.email = ['bob.usenakunov@gmail.com']
11
+ spec.summary = %q{Client for CDEK logistics service API}
12
+ spec.description = %q{Client for CDEK logistics service API}
13
+ spec.homepage = 'https://github.com/bob-frost/cdek_client'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'httparty', '~> 0.11'
22
+ spec.add_dependency 'nokogiri', '~> 1.5'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.0'
25
+ end
@@ -0,0 +1,153 @@
1
+ require 'cdek_client/client'
2
+
3
+ module CdekClient
4
+
5
+ extend self
6
+
7
+ HOSTS = {
8
+ primary: {
9
+ host: 'gw.edostavka.ru',
10
+ port: 11443
11
+ }.freeze,
12
+ secondary: {
13
+ host: 'lk.cdek.ru',
14
+ port: 11443
15
+ }.freeze,
16
+ calculator_primary: {
17
+ host: 'api.edostavka.ru',
18
+ port: 80
19
+ }.freeze,
20
+ calculator_secondary: {
21
+ host: 'lk.cdek.ru',
22
+ port: 8080
23
+ }.freeze
24
+ }.freeze
25
+
26
+ PATHS = {
27
+ pickup_points: 'pvzlist.php',
28
+ order_statuses: 'status_report_h.php',
29
+ order_infos: 'info_report.php',
30
+ new_orders: 'new_orders.php',
31
+ new_schedule: 'new_schedule.php',
32
+ call_courier: 'call_courier.php',
33
+ delete_orders: 'delete_orders.php',
34
+ orders_print: 'orders_print.php',
35
+ calculate: 'calculator/calculate_price_by_json.php'
36
+ }.freeze
37
+
38
+ RESPONSE_NORMALIZATION_RULES = {
39
+ pickup_points: {
40
+ CityCode: :to_i,
41
+ coordX: :to_f,
42
+ coordY: :to_f,
43
+ WeightLimit: {
44
+ WeightMin: :to_f,
45
+ WeightMax: :to_f
46
+ }.freeze
47
+ }.freeze,
48
+
49
+ order_statuses: {
50
+ DeliveryDate: :to_time,
51
+ ReturnDispatchNumber: :to_i,
52
+ Status: {
53
+ Date: :to_time,
54
+ Code: :to_i,
55
+ CityCode: :to_i,
56
+ State: {
57
+ Date: :to_time,
58
+ Code: :to_i,
59
+ CityCode: :to_i
60
+ }.freeze
61
+ }.freeze,
62
+ Reason: {
63
+ Date: :to_time,
64
+ Code: :to_i
65
+ }.freeze,
66
+ DelayReason: {
67
+ Date: :to_time,
68
+ Code: :to_i,
69
+ State: {
70
+ Date: :to_time,
71
+ Code: :to_i,
72
+ CityCode: :to_i
73
+ }.freeze
74
+ }.freeze,
75
+ Package: {
76
+ Item: {
77
+ DelivAmount: :to_i
78
+ }.freeze
79
+ }.freeze,
80
+ Attempt: {
81
+ ScheduleCode: :to_i
82
+ }.freeze,
83
+ Call: {
84
+ CallGood: {
85
+ Good: {
86
+ Date: :to_date,
87
+ DateDeliv: :to_date
88
+ }.freeze
89
+ }.freeze,
90
+ CallFail: {
91
+ Fail: {
92
+ Date: :to_date,
93
+ ReasonCode: :to_i
94
+ }.freeze
95
+ }.freeze,
96
+ CallDelay: {
97
+ Delay: {
98
+ Date: :to_date,
99
+ DateNext: :to_date
100
+ }.freeze
101
+ }.freeze
102
+ }.freeze
103
+ }.freeze,
104
+
105
+ order_infos: {
106
+ Date: :to_date,
107
+ TariffTypeCode: :to_i,
108
+ Weight: :to_f,
109
+ DeliverySum: :to_f,
110
+ DateLastChange: :to_time,
111
+ CashOnDeliv: :to_f,
112
+ CachOnDelivFac: :to_f,
113
+ SendCity: {
114
+ Code: :to_i
115
+ }.freeze,
116
+ RecCity: {
117
+ Code: :to_i
118
+ }.freeze,
119
+ AddedService: {
120
+ ServiceCode: :to_i,
121
+ Sum: :to_f
122
+ }.freeze
123
+ }.freeze,
124
+
125
+ calculate: {
126
+ price: :to_f,
127
+ deliveryPeriodMin: :to_i,
128
+ deliveryPeriodMax: :to_i,
129
+ deliveryDateMin: :to_date,
130
+ deliveryDateMax: :to_date,
131
+ tariffId: :to_i,
132
+ cashOnDelivery: :to_f,
133
+ priceByCurrency: :to_f
134
+ }.freeze
135
+
136
+ }.freeze
137
+
138
+ CALCULATOR_API_VERSION = '1.0'
139
+
140
+ TIME_FORMAT = '%Y-%m-%dT%H:%M:%S'
141
+
142
+ DATE_FORMAT = '%Y-%m-%d'
143
+
144
+ def generate_secure(formatted_date, password)
145
+ Digest::MD5.hexdigest("#{formatted_date}&#{password}")
146
+ end
147
+
148
+ def format_date(date_or_time)
149
+ format = date_or_time.is_a?(Time) || date_or_time.is_a?(DateTime) ? TIME_FORMAT : DATE_FORMAT
150
+ date_or_time.strftime(format)
151
+ end
152
+
153
+ end
@@ -0,0 +1,120 @@
1
+ require 'httparty'
2
+ require 'nokogiri'
3
+
4
+ require 'cdek_client'
5
+ require 'cdek_client/errors'
6
+ require 'cdek_client/result'
7
+ require 'cdek_client/util'
8
+
9
+ module CdekClient
10
+ class AbstractClient
11
+
12
+ protected
13
+
14
+ def url_for(host_key, path_key)
15
+ URI.join("http://#{CdekClient::HOSTS[host_key][:host]}:#{CdekClient::HOSTS[host_key][:port]}", CdekClient::PATHS[path_key]).to_s
16
+ end
17
+
18
+ def response_normalization_rules_for(key)
19
+ CdekClient::RESPONSE_NORMALIZATION_RULES[key]
20
+ end
21
+
22
+ def normalize_request_data(data)
23
+ case data
24
+ when Hash
25
+ result = {}
26
+ data.each do |key, value|
27
+ result[key.to_sym] = normalize_request_data(value)
28
+ end
29
+ return result
30
+ when Array
31
+ result = []
32
+ data.each do |value|
33
+ result.push normalize_request_data(value)
34
+ end
35
+ return result
36
+ when Date, Time
37
+ return CdekClient.format_date data
38
+ else
39
+ return data
40
+ end
41
+ end
42
+
43
+ def normalize_response_data(data, rules, keypath = [])
44
+ if data.nil? || (data.is_a?(String) && data.strip.empty?)
45
+ return nil
46
+ end
47
+
48
+ case data
49
+ when Hash
50
+ result = {}
51
+ data.each do |key, value|
52
+ key = key.to_sym
53
+ result[key] = normalize_response_data(value, rules, keypath + [key])
54
+ end
55
+ return result
56
+ when Array
57
+ result = []
58
+ data.each do |value|
59
+ result.push normalize_response_data(value, rules, keypath)
60
+ end
61
+ return result
62
+ else
63
+ rule = rules.nil? ? nil : Util.hash_value_at_keypath(rules, keypath)
64
+ case rule
65
+ when :to_i, :to_f
66
+ return data.send rule
67
+ when :to_date
68
+ begin
69
+ return Date.parse data
70
+ rescue ArgumentError => e
71
+ puts "Couldn't parse date '#{data}' at #{keypath.join '.'} with #{e.class.name}: #{e.message}!"
72
+ return data
73
+ end
74
+ when :to_time
75
+ begin
76
+ return Time.parse data
77
+ rescue ArgumentError => e
78
+ puts "Couldn't parse time '#{data}' at #{keypath.join '.'} with #{e.class.name}: #{e.message}!"
79
+ return data
80
+ end
81
+ else
82
+ return data
83
+ end
84
+ end
85
+ end
86
+
87
+ def raw_request(url, retry_url, method, request_params, params)
88
+ if !Util.blank?(params)
89
+ if method == :post
90
+ request_params = request_params.merge body: params
91
+ else
92
+ request_params = request_params.merge query: params
93
+ end
94
+ end
95
+
96
+ begin
97
+ response = HTTParty.send method, url, request_params
98
+ if response.code == 200
99
+ return CdekClient::Result.new response, response.body
100
+ else
101
+ raise CdekClient::ResponseError.new response.code, response.message
102
+ end
103
+ rescue CdekClient::ResponseError, HTTParty::ResponseError => e
104
+ if Util.blank? retry_url
105
+ error = e.is_a?(CdekClient::ResponseError) ? e : (CdekClient::ResponseError.new e.response.code, e.response.message)
106
+ return CdekClient::Result.new response, response.body, [error]
107
+ else
108
+ return raw_request url, nil, method, request_params, nil
109
+ end
110
+ rescue Timeout::Error, Errno::ETIMEDOUT => e
111
+ if Util.blank? retry_url
112
+ return CdekClient::Result.new response, response.body, [e]
113
+ else
114
+ return raw_request url, nil, method, request_params, nil
115
+ end
116
+ end
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,68 @@
1
+ require 'httparty'
2
+ require 'json'
3
+
4
+ require 'cdek_client/abstract_client'
5
+ require 'cdek_client/calculator_errors'
6
+ require 'cdek_client/util'
7
+
8
+ module CdekClient
9
+
10
+ class CalculatorClient < AbstractClient
11
+
12
+ def initialize(account = nil, password = nil)
13
+ @account = account
14
+ @password = password
15
+ end
16
+
17
+ def calculate(params)
18
+ params = normalize_request_data params
19
+ formatted_date_execute = if params[:dateExecute].is_a?(Date) || params[:dateExecute].is_a?(Time)
20
+ CdekClient.format_date params[:dateExecute]
21
+ elsif !Util.blank? params[:dateExecute]
22
+ params[:dateExecute]
23
+ else
24
+ CdekClient.format_date Date.today
25
+ end
26
+ params.merge!(
27
+ version: CdekClient::CALCULATOR_API_VERSION,
28
+ dateExecute: formatted_date_execute
29
+ )
30
+ if !@account.nil? && !@password.nil?
31
+ params.merge!({
32
+ authLogin: @account,
33
+ secure: CdekClient.generate_secure(formatted_date_execute, @password)
34
+ })
35
+ end
36
+ result = request url_for(:calculator_primary, :calculate), url_for(:calculator_secondary, :calculate), :post, params
37
+ if result.errors.any?
38
+ result.set_data({})
39
+ elsif result.data.has_key?(:error)
40
+ Util.array_wrap(result.data[:error]).each do |error_data|
41
+ error = Calculator.get_api_error error_data[:code], error_data[:text]
42
+ result.add_error error
43
+ end
44
+ result.set_data({})
45
+ else
46
+ normalized_data = normalize_response_data result.data[:result], response_normalization_rules_for(:calculate)
47
+ result.set_data normalized_data
48
+ end
49
+ return result
50
+ end
51
+
52
+ private
53
+
54
+ def request(url, retry_url, method, params = {})
55
+ params = params.to_json
56
+ request_params = {
57
+ headers: { 'Content-Type' => 'application/json' }
58
+ }
59
+ result = raw_request url, retry_url, method, {}, params
60
+ if !Util.blank? result.data
61
+ data = Util.deep_symbolize_keys JSON.parse(result.data)
62
+ result.set_data data
63
+ end
64
+ result
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,73 @@
1
+ require 'cdek_client/errors'
2
+
3
+ module CdekClient
4
+ module Calculator
5
+
6
+ class Error < CdekClient::Error; end
7
+
8
+ class APIError < Error; end
9
+
10
+ class UnkownAPIError < APIError; end
11
+
12
+ class ServerError < APIError; end
13
+
14
+ class ApiVersionError < APIError; end
15
+
16
+ class AuthError < APIError; end
17
+
18
+ class DeliveryImpossibleError < APIError; end
19
+
20
+ class PlaceParamsError < APIError; end
21
+
22
+ class PlaceEmptyError < APIError; end
23
+
24
+ class TariffEmptyError < APIError; end
25
+
26
+ class SenderCityEmptyError < APIError; end
27
+
28
+ class ReceiverCityEmptyError < APIError; end
29
+
30
+ class DateEmptyError < APIError; end
31
+
32
+ class DeliveryTypeError < APIError; end
33
+
34
+ class FormatError < APIError; end
35
+
36
+ class DecodeError < APIError; end
37
+
38
+ class SenderPostcodeNotFoundError < APIError; end
39
+
40
+ class SenderPostcodeAmbigiousError < APIError; end
41
+
42
+ class ReceiverPostcodeNotFoundError < APIError; end
43
+
44
+ class ReceiverPostcodeAmbigiousError < APIError; end
45
+
46
+ def self.get_api_error(code, message)
47
+ code = code.to_i if !code.is_a?(Integer) && code.to_s =~ /^\d+$/
48
+ klass = API_ERROR_MAPPINGS[code] || UnkownAPIError
49
+ klass.new code, message
50
+ end
51
+
52
+ API_ERROR_MAPPINGS = {
53
+ 0 => ServerError,
54
+ 1 => ApiVersionError,
55
+ 2 => AuthError,
56
+ 3 => DeliveryImpossibleError,
57
+ 4 => PlaceParamsError,
58
+ 5 => PlaceEmptyError,
59
+ 6 => TariffEmptyError,
60
+ 7 => SenderCityEmptyError,
61
+ 8 => ReceiverCityEmptyError,
62
+ 9 => DateEmptyError,
63
+ 10 => DeliveryTypeError,
64
+ 11 => FormatError,
65
+ 12 => DecodeError,
66
+ 13 => SenderPostcodeNotFoundError,
67
+ 14 => SenderPostcodeAmbigiousError,
68
+ 15 => ReceiverPostcodeNotFoundError,
69
+ 16 => ReceiverPostcodeAmbigiousError
70
+ }
71
+
72
+ end
73
+ end
@@ -0,0 +1,256 @@
1
+ require 'httparty'
2
+ require 'nokogiri'
3
+
4
+ require 'cdek_client/abstract_client'
5
+ require 'cdek_client/calculator_client'
6
+ require 'cdek_client/util'
7
+
8
+ module CdekClient
9
+ class Client < AbstractClient
10
+
11
+ def initialize(account = nil, password = nil)
12
+ @account = account
13
+ @password = password
14
+ end
15
+
16
+ def pickup_points(params = {})
17
+ params = normalize_request_data params
18
+ result = request url_for(:primary, :pickup_points), url_for(:secondary, :pickup_points), :get, params
19
+ if result.errors.any?
20
+ result.set_data []
21
+ return result
22
+ end
23
+ if result.data[:PvzList].has_key? :ErrorCode
24
+ error = CdekClient.get_api_error result.data[:PvzList][:ErrorCode], result.data[:PvzList][:Msg]
25
+ result.add_error error
26
+ result.set_data []
27
+ else
28
+ normalized_data = Util.array_wrap result.data[:PvzList][:Pvz]
29
+ normalized_data = normalize_response_data normalized_data, response_normalization_rules_for(:pickup_points)
30
+ result.set_data normalized_data
31
+ end
32
+ result
33
+ end
34
+
35
+ def order_statuses(params = {})
36
+ params = normalize_request_data params
37
+ params = { StatusReport: params }
38
+ result = authorized_request url_for(:primary, :order_statuses), url_for(:secondary, :order_statuses), params
39
+ if result.errors.any?
40
+ result.set_data []
41
+ return result
42
+ end
43
+ if result.data[:StatusReport].has_key? :ErrorCode
44
+ error = CdekClient.get_api_error result.data[:StatusReport][:ErrorCode], result.data[:StatusReport][:Msg]
45
+ result.add_error error
46
+ result.set_data []
47
+ else
48
+ normalized_data = Util.array_wrap result.data[:StatusReport][:Order]
49
+ normalized_data = normalize_response_data normalized_data, response_normalization_rules_for(:order_statuses)
50
+ result.set_data normalized_data
51
+ end
52
+ result
53
+ end
54
+
55
+ def order_infos(params)
56
+ params = normalize_request_data params
57
+ params = { InfoRequest: params }
58
+ result = authorized_request url_for(:primary, :order_infos), url_for(:secondary, :order_infos), params
59
+ if result.errors.any?
60
+ result.set_data []
61
+ return result
62
+ end
63
+ if result.data.has_key? :response
64
+ result.data[:response].values.each do |error_data|
65
+ error = CdekClient.get_api_error error_data[:ErrorCode], error_data[:Msg]
66
+ result.add_error error
67
+ end
68
+ result.set_data []
69
+ elsif result.data.has_key?(:InfoReport) && result.data[:InfoReport].is_a?(Hash)
70
+ normalized_data = Util.array_wrap result.data[:InfoReport][:Order]
71
+ normalized_data = normalize_response_data normalized_data, response_normalization_rules_for(:order_infos)
72
+ result.set_data normalized_data
73
+ else
74
+ result.set_data []
75
+ end
76
+ result
77
+ end
78
+
79
+ def new_orders(params)
80
+ params = normalize_request_data params
81
+ params[:OrderCount] = params[:Order].is_a?(Array) ? params[:Order].length : 1
82
+ params = { DeliveryRequest: params }
83
+ result = authorized_request url_for(:primary, :new_orders), url_for(:secondary, :new_orders), params
84
+ if result.errors.any?
85
+ result.set_data []
86
+ return result
87
+ end
88
+ normalized_data = []
89
+ if result.data[:response].has_key? :DeliveryRequest
90
+ Util.array_wrap(result.data[:response][:DeliveryRequest]).each do |error_data|
91
+ error = CdekClient.get_api_error error_data[:ErrorCode], error_data[:Msg]
92
+ result.add_error error
93
+ end
94
+ end
95
+ if result.data[:response].has_key? :Order
96
+ Util.array_wrap(result.data[:response][:Order]).each do |order_data|
97
+ if order_data.has_key? :ErrorCode
98
+ error = CdekClient.get_api_error order_data[:ErrorCode], order_data[:Msg]
99
+ result.add_error error
100
+ elsif order_data.has_key? :Number
101
+ normalized_order_data = normalize_response_data order_data, response_normalization_rules_for(:new_orders)
102
+ normalized_data.push normalized_order_data
103
+ end
104
+ end
105
+ end
106
+ result.set_data normalized_data
107
+ result
108
+ end
109
+
110
+ def new_schedule(params)
111
+ params = normalize_request_data params
112
+ params[:OrderCount] = params[:Order].is_a?(Array) ? params[:Order].length : 1
113
+ params = { ScheduleRequest: params }
114
+ result = authorized_request url_for(:primary, :new_schedule), url_for(:secondary, :new_schedule), params
115
+ if result.errors.any?
116
+ result.set_data []
117
+ return result
118
+ end
119
+ normalized_data = []
120
+ if result.data[:response].has_key? :Order
121
+ Util.array_wrap(result.data[:response][:Order]).each do |error_data|
122
+ error = CdekClient.get_api_error error_data[:ErrorCode], error_data[:Msg]
123
+ result.add_error error
124
+ end
125
+ end
126
+ if result.data[:response].has_key? :ScheduleRequest
127
+ Util.array_wrap(result.data[:response][:ScheduleRequest]).each do |schedule_data|
128
+ if schedule_data.has_key? :ErrorCode
129
+ error = CdekClient.get_api_error schedule_data[:ErrorCode], schedule_data[:Msg]
130
+ result.add_error error
131
+ elsif schedule_data.has_key? :Msg
132
+ normalized_schedule_data = normalize_response_data schedule_data, response_normalization_rules_for(:new_schedule)
133
+ normalized_data.push normalized_schedule_data
134
+ end
135
+ end
136
+ end
137
+ result.set_data normalized_data
138
+ result
139
+ end
140
+
141
+ def call_courier(params)
142
+ params = normalize_request_data params
143
+ params[:CallCount] = params[:Call].is_a?(Array) ? params[:Call].length : 1
144
+ params = { CallCourier: params }
145
+ result = authorized_request url_for(:primary, :call_courier), url_for(:secondary, :call_courier), params
146
+ if result.errors.any?
147
+ result.set_data []
148
+ return result
149
+ end
150
+ normalized_data = []
151
+ if result.data[:response].has_key? :CallCourier
152
+ Util.array_wrap(result.data[:response][:CallCourier]).each do |error_data|
153
+ next unless error_data.has_key?(:ErrorCode)
154
+ error = CdekClient.get_api_error error_data[:ErrorCode], error_data[:Msg]
155
+ result.add_error error
156
+ end
157
+ end
158
+ if result.data[:response].has_key? :Call
159
+ Util.array_wrap(result.data[:response][:Call]).each do |call_data|
160
+ if call_data.has_key? :ErrorCode
161
+ error = CdekClient.get_api_error call_data[:ErrorCode], call_data[:Msg]
162
+ result.add_error error
163
+ elsif call_data.has_key? :Number
164
+ normalized_call_data = normalize_response_data call_data, response_normalization_rules_for(:call_courier)
165
+ normalized_data.push normalized_call_data
166
+ end
167
+ end
168
+ end
169
+ result.set_data normalized_data
170
+ result
171
+ end
172
+
173
+ def delete_orders(params)
174
+ params = normalize_request_data params
175
+ params[:OrderCount] = params[:Order].is_a?(Array) ? params[:Order].length : 1
176
+ params = { DeleteRequest: params }
177
+ result = authorized_request url_for(:primary, :delete_orders), url_for(:secondary, :delete_orders), params
178
+ # Currently API returns '500 - internal server error' for some invalid requests here.
179
+ # Continue processing data if it is such error but response data is present
180
+ if result.errors.any? && (result.errors.length > 1 || result.errors[0].code != 500 || !result.data.is_a?(Hash) || !result.data.has_key?(:response))
181
+ result.set_data []
182
+ return result
183
+ end
184
+
185
+ normalized_data = []
186
+ Util.array_wrap(result.data[:response][:DeleteRequest]).each do |delete_data|
187
+ if delete_data.has_key? :ErrorCode
188
+ error = CdekClient.get_api_error delete_data[:ErrorCode], delete_data[:Msg]
189
+ result.add_error error
190
+ elsif delete_data.has_key? :Number
191
+ normalized_delete_data = normalize_response_data delete_data, response_normalization_rules_for(:delete_orders)
192
+ normalized_data.push normalized_delete_data
193
+ end
194
+ end
195
+ result.set_data normalized_data
196
+ result
197
+ end
198
+
199
+ def orders_print(params)
200
+ params = normalize_request_data params
201
+ params[:OrderCount] = params[:Order].is_a?(Array) ? params[:Order].length : 1
202
+ params = build_authorized_request_params OrdersPrint: params
203
+ result = raw_request url_for(:primary, :orders_print), url_for(:secondary, :orders_print), :post, {}, params
204
+ errors_hash = Util.xml_to_hash(result.data) rescue nil
205
+ if !errors_hash.nil? && errors_hash.has_key?(:response)
206
+ [:OrdersPrint, :Order].each do |key|
207
+ Util.array_wrap(errors_hash[:response][key]).each do |error_data|
208
+ next unless error_data.has_key?(:ErrorCode)
209
+ error = CdekClient.get_api_error error_data[:ErrorCode], error_data[:Msg]
210
+ result.add_error error
211
+ end
212
+ end
213
+ result.set_data nil
214
+ end
215
+ result
216
+ end
217
+
218
+ def calculate_price(params)
219
+ calculator.calculate params
220
+ end
221
+
222
+ private
223
+
224
+ def authorized_request(url, retry_url, params = {})
225
+ params = build_authorized_request_params params
226
+ request url, retry_url, :post, params
227
+ end
228
+
229
+ def request(url, retry_url, method, params = {})
230
+ result = raw_request url, retry_url, method, {}, params
231
+ if !Util.blank? result.data
232
+ result.set_data Util.xml_to_hash(result.data)
233
+ end
234
+ result
235
+ end
236
+
237
+ def build_authorized_request_params(params)
238
+ root_key = params.keys.first
239
+ formatted_date = CdekClient.format_date Time.now.utc
240
+ secure = CdekClient.generate_secure formatted_date, @password
241
+ params = {
242
+ root_key => params[root_key].merge(
243
+ Date: formatted_date,
244
+ Account: @account,
245
+ Secure: secure
246
+ )
247
+ }
248
+ { xml_request: Util.hash_to_xml(params) }
249
+ end
250
+
251
+ def calculator
252
+ @calculator ||= CalculatorClient.new @account, @password
253
+ end
254
+
255
+ end
256
+ end