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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +418 -0
- data/Rakefile +2 -0
- data/cdek_client.gemspec +25 -0
- data/lib/cdek_client.rb +153 -0
- data/lib/cdek_client/abstract_client.rb +120 -0
- data/lib/cdek_client/calculator_client.rb +68 -0
- data/lib/cdek_client/calculator_errors.rb +73 -0
- data/lib/cdek_client/client.rb +256 -0
- data/lib/cdek_client/errors.rb +386 -0
- data/lib/cdek_client/result.rb +22 -0
- data/lib/cdek_client/util.rb +125 -0
- data/lib/cdek_client/version.rb +3 -0
- metadata +101 -0
data/Rakefile
ADDED
data/cdek_client.gemspec
ADDED
@@ -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
|
data/lib/cdek_client.rb
ADDED
@@ -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
|