iml_client 0.0.1 → 0.0.2
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 +8 -8
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +148 -0
- data/Rakefile +2 -0
- data/iml_client.gemspec +24 -0
- data/lib/iml_client.rb +50 -0
- data/lib/iml_client/abstract_api_client.rb +135 -0
- data/lib/iml_client/client.rb +74 -0
- data/lib/iml_client/errors.rb +18 -0
- data/lib/iml_client/list_api_client.rb +79 -0
- data/lib/iml_client/rest_api_client.rb +79 -0
- data/lib/iml_client/result.rb +21 -0
- data/lib/iml_client/util.rb +41 -0
- data/lib/iml_client/version.rb +3 -0
- metadata +21 -6
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZTFlMGMwZmVhY2M1MWE0YWFiNzIzYmIwZGNlNDUzYTg3NTNmM2M3Yg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZjVhN2RjYzQxMWE2OTViMWE3OWNmNGNhMjBlMTMxZWJlODJhYzAxMg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NDdhYzJhYmVkMjJlNTlhYjcxOGI2MzgwMTg5OWJkNDBmM2I5NDc3NGQ0MzBj
|
10
|
+
MWI1NTI3ODBmYmYyYTAyYTAxNWZjMmE5MDAxMTkwYmNkMjI5ZTBlZWM2NTFj
|
11
|
+
NzcxZDQ0MTRjZTI5YTkzMjU2OWY1YTVmNTgzOTE3ZWM0NDY5MzI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YTdjOGM5ZDMwNTQyMWVlMjdjNGFhN2MwMjVjOGNjNWFjNDE4YmEyMDg5ZWM1
|
14
|
+
YmY1NjZiYjI5Mzc1MWNkOTlkMDkyYWJkOGExMWVmNjNiNjY5NmQ4OWIzZTM5
|
15
|
+
NTYwNGNkY2IyNTkzZjE3NGZhOWMwM2Y4MWZmOGI1NTRhMWY4Nzk=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 bob-frost
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
# ImlClient
|
2
|
+
Ruby клиент для API службы доставки IML ([www.iml.ru](http://iml.ru/)).
|
3
|
+
|
4
|
+
## Установка
|
5
|
+
Добавить в Gemfile:
|
6
|
+
|
7
|
+
gem 'iml_client'
|
8
|
+
|
9
|
+
И выполнить:
|
10
|
+
|
11
|
+
$ bundle
|
12
|
+
|
13
|
+
Или установить вручную:
|
14
|
+
|
15
|
+
$ gem install iml_client
|
16
|
+
|
17
|
+
## Начало работы
|
18
|
+
|
19
|
+
Создать инстанс класса `ImlClient::Client`:
|
20
|
+
```ruby
|
21
|
+
client = ImlClient::Client.new ВАШ_ЛОГИН, ВАШ_ПАРОЛЬ
|
22
|
+
```
|
23
|
+
В тестовом режиме:
|
24
|
+
```
|
25
|
+
client = ImlClient::Client.new ВАШ_ЛОГИН, ВАШ_ПАРОЛЬ, test_mode: true
|
26
|
+
```
|
27
|
+
|
28
|
+
Вызовы возвращают объект класса `ImlClient::Result`. Результат хранится в атрибуте `data`, ошибки (если присутствуют) в `errors`. Полный результат запроса ([HTTParty](https://github.com/jnunemaker/httparty)) можно получить из атрибута `response`. Например:
|
29
|
+
```ruby
|
30
|
+
result = client.orders DeliveryDateStart: Date.new(2015, 9, 20), DeliveryDateEnd: Date.new(2015, 9, 30)
|
31
|
+
result.errors.any? # => false
|
32
|
+
result.data.length # => 20
|
33
|
+
result.data.each do |order|
|
34
|
+
puts order[:Job]
|
35
|
+
end
|
36
|
+
|
37
|
+
result = client.create_order Job: '24', CustomerOrder: 'R123456', Contact: 'John Doe', Phone: '123-456-789', RegionCodeFrom: 'МОСКВА', RegionCodeTo: 'ВИНТЕРФЕЛЛ'
|
38
|
+
result.data # => {}
|
39
|
+
result.errors.length # => 2
|
40
|
+
result.errors.each do |error|
|
41
|
+
puts "#{error.code} - #{error.message}"
|
42
|
+
end
|
43
|
+
# RegionCodeTo - Неверно указан регион получения!
|
44
|
+
# Address - Адрес указан не верно!
|
45
|
+
```
|
46
|
+
|
47
|
+
## Ошибки
|
48
|
+
Классы ошибок наследуют от `ImlClient::Error`:
|
49
|
+
* StandardError
|
50
|
+
* ImlClient::Error
|
51
|
+
* ImlClient::ResponseError
|
52
|
+
* ImlClient::APIError
|
53
|
+
|
54
|
+
Например:
|
55
|
+
```ruby
|
56
|
+
# ImlClient::ResponseError
|
57
|
+
error.code # => 500
|
58
|
+
error.message # => internal server error
|
59
|
+
|
60
|
+
# ImlClient::APIError
|
61
|
+
error.code # => RegionCodeTo
|
62
|
+
error.message # => Неверно указан регион получения!
|
63
|
+
```
|
64
|
+
|
65
|
+
## Методы
|
66
|
+
Для получения детальной информации о формате передаваемых и возвращаемых данных ознакомьтесь с официальной документацией к API: [api.iml.ru](http://api.iml.ru), [list.iml.ru](http://list.iml.ru).
|
67
|
+
|
68
|
+
Даты можно передавать как объекты класса `Date`, так и как строки в формате `%d.%m.%Y`.
|
69
|
+
|
70
|
+
#### Создание нового заказа
|
71
|
+
```ruby
|
72
|
+
client.create_order params
|
73
|
+
```
|
74
|
+
|
75
|
+
#### Список заказов
|
76
|
+
```ruby
|
77
|
+
client.orders
|
78
|
+
client.orders filter_params
|
79
|
+
```
|
80
|
+
|
81
|
+
#### Список статусов заказов
|
82
|
+
```ruby
|
83
|
+
client.order_statuses
|
84
|
+
client.order_statuses filter_params
|
85
|
+
```
|
86
|
+
|
87
|
+
#### Подсчёт стоимости доставки
|
88
|
+
```ruby
|
89
|
+
client.calculate_price params
|
90
|
+
```
|
91
|
+
|
92
|
+
#### Список складов
|
93
|
+
```ruby
|
94
|
+
client.locations
|
95
|
+
client.locations filter_params
|
96
|
+
```
|
97
|
+
|
98
|
+
Помимо параметров фильтрации, предоставляемых API, здесь также доступны два дополнительных параметра:
|
99
|
+
- `IncludeNotOpened`- `boolean`. Включить в список еще не открывшиеся склады (c `OpeningDate` больше текущей даты). По умолчанию `false`.
|
100
|
+
- `IncludeClosed`- `boolean`. Включить в список закрывшиеся склады (c `ClosingDate` меньше или равным текущей дате). По умолчанию `false`.
|
101
|
+
|
102
|
+
#### Список заблокированных регионов IML, в разрезе услуг
|
103
|
+
```ruby
|
104
|
+
client.exception_service_regions
|
105
|
+
client.exception_service_regions filter_params
|
106
|
+
```
|
107
|
+
|
108
|
+
Помимо параметров фильтрации, предоставляемых API, здесь также доступны два дополнительных параметра:
|
109
|
+
- `IncludeNotOpened`- `boolean`. Включить в список еще не заблокированные регионы (c `Open` больше текущей даты). По умолчанию `false`.
|
110
|
+
- `IncludeEnded`- `boolean`. Включить в список уже разблокированные регионы (c `End` меньше или равным текущей дате). По умолчанию `false`.
|
111
|
+
|
112
|
+
#### Список регионов IML
|
113
|
+
```ruby
|
114
|
+
client.regions
|
115
|
+
```
|
116
|
+
|
117
|
+
#### Список пунктов самовывоза
|
118
|
+
```ruby
|
119
|
+
client.pickup_points
|
120
|
+
client.pickup_points filter_params
|
121
|
+
```
|
122
|
+
|
123
|
+
Помимо параметров фильтрации, предоставляемых API, здесь также доступны два дополнительных параметра:
|
124
|
+
- `IncludeNotOpened`- `boolean`. Включить в список еще не открывшиеся пункты (c `OpeningDate` больше текущей даты). По умолчанию `false`.
|
125
|
+
- `IncludeClosed`- `boolean`. Включить в список закрывшиеся пункты (c `ClosingDate` меньше или равным текущей дате). По умолчанию `false`.
|
126
|
+
|
127
|
+
#### Справочник статусов
|
128
|
+
```ruby
|
129
|
+
client.status_types
|
130
|
+
```
|
131
|
+
|
132
|
+
#### Справочник почтовых индексов
|
133
|
+
```ruby
|
134
|
+
client.post_codes
|
135
|
+
```
|
136
|
+
|
137
|
+
#### Список услуг
|
138
|
+
```ruby
|
139
|
+
client.services
|
140
|
+
```
|
141
|
+
|
142
|
+
## TODO
|
143
|
+
- Тесты
|
144
|
+
|
145
|
+
## Ссылки
|
146
|
+
- [iml.ru](http://iml.ru/) - Оффициальный сайт IML.
|
147
|
+
- [api.iml.ru](http://api.iml.ru/) - Документация к API IML.
|
148
|
+
- [list.iml.ru](http://list.iml.ru/) - Документация к API справочного сервиса IML.
|
data/Rakefile
ADDED
data/iml_client.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'iml_client/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'iml_client'
|
8
|
+
spec.version = ImlClient::VERSION
|
9
|
+
spec.authors = ['Babur Usenakunov']
|
10
|
+
spec.email = ['bob.usenakunov@gmail.com']
|
11
|
+
spec.summary = %q{Client for IML logistics service API}
|
12
|
+
spec.description = %q{Client for IML logistics service API}
|
13
|
+
spec.homepage = 'https://github.com/bob-frost/iml_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
|
+
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.0'
|
24
|
+
end
|
data/lib/iml_client.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'iml_client/client'
|
2
|
+
|
3
|
+
module ImlClient
|
4
|
+
|
5
|
+
extend self
|
6
|
+
|
7
|
+
REST_API_HOST = 'api.iml.ru'
|
8
|
+
LIST_API_HOST = 'list.iml.ru'
|
9
|
+
|
10
|
+
API_PATHS = {
|
11
|
+
orders: 'json/GetOrders',
|
12
|
+
order_statuses: 'json/GetStatuses',
|
13
|
+
create_order: 'json/CreateOrder',
|
14
|
+
calculate_price: 'json/GetPrice',
|
15
|
+
locations: 'Location',
|
16
|
+
exception_service_regions: 'ExceptionServiceRegion',
|
17
|
+
regions: 'region',
|
18
|
+
pickup_points: 'SD',
|
19
|
+
status_types: 'status',
|
20
|
+
post_codes: 'PostCode',
|
21
|
+
services: 'service'
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
RESPONSE_NORMALIZATION_RULES = {
|
25
|
+
orders: {
|
26
|
+
DeliveryDate: :to_date
|
27
|
+
}.freeze,
|
28
|
+
order_statuses: {
|
29
|
+
StatusDate: :to_date
|
30
|
+
}.freeze,
|
31
|
+
create_order: {
|
32
|
+
DeliveryDate: :to_date
|
33
|
+
}.freeze,
|
34
|
+
locations: {
|
35
|
+
OpeningDate: :to_date,
|
36
|
+
ClosingDate: :to_date
|
37
|
+
}.freeze,
|
38
|
+
exception_service_regions: {
|
39
|
+
Open: :to_date,
|
40
|
+
End: :to_date
|
41
|
+
}.freeze,
|
42
|
+
pickup_points: {
|
43
|
+
OpeningDate: :to_date,
|
44
|
+
ClosingDate: :to_date
|
45
|
+
}.freeze
|
46
|
+
}.freeze
|
47
|
+
|
48
|
+
REQUEST_DATE_FORMAT = '%d.%m.%Y'
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require 'iml_client/errors'
|
5
|
+
require 'iml_client/result'
|
6
|
+
require 'iml_client/util'
|
7
|
+
|
8
|
+
module ImlClient
|
9
|
+
class AbstractApiClient
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def format_request_date(date_or_time)
|
14
|
+
date_or_time.strftime ImlClient::REQUEST_DATE_FORMAT
|
15
|
+
end
|
16
|
+
|
17
|
+
def normalize_request_data(data)
|
18
|
+
case data
|
19
|
+
when Hash
|
20
|
+
result = {}
|
21
|
+
data.each do |key, value|
|
22
|
+
result[key.to_sym] = normalize_request_data value
|
23
|
+
end
|
24
|
+
return result
|
25
|
+
when Array
|
26
|
+
result = []
|
27
|
+
data.each do |value|
|
28
|
+
result.push normalize_request_data(value)
|
29
|
+
end
|
30
|
+
return result
|
31
|
+
when Date, Time
|
32
|
+
return format_request_date data
|
33
|
+
else
|
34
|
+
return data
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def normalize_response_data(data, rules, keypath = [])
|
39
|
+
if data.nil? || (data.is_a?(String) && data.strip.empty?)
|
40
|
+
return nil
|
41
|
+
end
|
42
|
+
|
43
|
+
case data
|
44
|
+
when Hash
|
45
|
+
result = {}
|
46
|
+
data.each do |key, value|
|
47
|
+
key = key.to_sym
|
48
|
+
result[key] = normalize_response_data value, rules, keypath + [key]
|
49
|
+
end
|
50
|
+
return result
|
51
|
+
when Array
|
52
|
+
result = []
|
53
|
+
data.each do |value|
|
54
|
+
result.push normalize_response_data(value, rules, keypath)
|
55
|
+
end
|
56
|
+
return result
|
57
|
+
else
|
58
|
+
rule = rules.nil? ? nil : Util.hash_value_at_keypath(rules, keypath)
|
59
|
+
case rule
|
60
|
+
# when :to_i, :to_f
|
61
|
+
# return data.send rule
|
62
|
+
when :to_date
|
63
|
+
begin
|
64
|
+
return Date.parse data
|
65
|
+
rescue ArgumentError => e
|
66
|
+
puts "Couldn't parse date '#{data}' at #{keypath.join '.'} with #{e.class.name}: #{e.message}!"
|
67
|
+
return data
|
68
|
+
end
|
69
|
+
# when :to_time
|
70
|
+
# begin
|
71
|
+
# return Time.parse data
|
72
|
+
# rescue ArgumentError => e
|
73
|
+
# puts "Couldn't parse time '#{data}' at #{keypath.join '.'} with #{e.class.name}: #{e.message}!"
|
74
|
+
# return data
|
75
|
+
# end
|
76
|
+
else
|
77
|
+
return data
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def host
|
83
|
+
raise '`host` method should be defined in child class'
|
84
|
+
end
|
85
|
+
|
86
|
+
def url_for(key)
|
87
|
+
URI.join("https://#{host}", ImlClient::API_PATHS[key]).to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
def response_normalization_rules_for(key)
|
91
|
+
ImlClient::RESPONSE_NORMALIZATION_RULES[key]
|
92
|
+
end
|
93
|
+
|
94
|
+
def request(url, method, request_params, params)
|
95
|
+
raise '`request` method should be defined in child class'
|
96
|
+
end
|
97
|
+
|
98
|
+
def request_and_normalize(url, method, request_params, params, normalization_rules, empty_data)
|
99
|
+
result = request url, method, request_params, params
|
100
|
+
if result.errors.any?
|
101
|
+
result.set_data empty_data
|
102
|
+
else
|
103
|
+
normalized_data = normalize_response_data result.data, normalization_rules
|
104
|
+
result.set_data normalized_data
|
105
|
+
end
|
106
|
+
result
|
107
|
+
end
|
108
|
+
|
109
|
+
def raw_request(url, method, request_params, params)
|
110
|
+
if !Util.blank?(params)
|
111
|
+
if method == :post
|
112
|
+
request_params = request_params.merge body: params.to_json
|
113
|
+
else
|
114
|
+
request_params = request_params.merge query: params
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
begin
|
119
|
+
response = HTTParty.send method, url, request_params
|
120
|
+
if response.code == 200
|
121
|
+
return ImlClient::Result.new response, response.parsed_response
|
122
|
+
else
|
123
|
+
error = ImlClient::ResponseError.new response.code, response.message
|
124
|
+
return ImlClient::Result.new response, nil, [error]
|
125
|
+
end
|
126
|
+
rescue HTTParty::ResponseError => e
|
127
|
+
error = ImlClient::ResponseError.new e.response.code, e.response.message
|
128
|
+
return ImlClient::Result.new e.response, nil, [error]
|
129
|
+
rescue Timeout::Error, Errno::ETIMEDOUT => e
|
130
|
+
return ImlClient::Result.new nil, nil, [e]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'iml_client/list_api_client'
|
2
|
+
require 'iml_client/rest_api_client'
|
3
|
+
require 'iml_client/util'
|
4
|
+
|
5
|
+
module ImlClient
|
6
|
+
class Client
|
7
|
+
|
8
|
+
def initialize(login, password, options = {})
|
9
|
+
@login = login
|
10
|
+
@password = password
|
11
|
+
options = Util.symbolize_keys options
|
12
|
+
@test_mode = !!options[:test_mode]
|
13
|
+
end
|
14
|
+
|
15
|
+
def orders(params = {})
|
16
|
+
rest_api_client.orders params
|
17
|
+
end
|
18
|
+
|
19
|
+
def order_statuses(params = {})
|
20
|
+
rest_api_client.order_statuses params
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_order(params)
|
24
|
+
rest_api_client.create_order params
|
25
|
+
end
|
26
|
+
|
27
|
+
def calculate_price(params)
|
28
|
+
rest_api_client.calculate_price params
|
29
|
+
end
|
30
|
+
|
31
|
+
def locations(params = {})
|
32
|
+
list_api_client.locations params
|
33
|
+
end
|
34
|
+
|
35
|
+
def exception_service_regions(params = {})
|
36
|
+
list_api_client.exception_service_regions params
|
37
|
+
end
|
38
|
+
|
39
|
+
def regions
|
40
|
+
list_api_client.regions
|
41
|
+
end
|
42
|
+
|
43
|
+
def pickup_points(params = {})
|
44
|
+
list_api_client.pickup_points params
|
45
|
+
end
|
46
|
+
|
47
|
+
def status_types
|
48
|
+
list_api_client.status_types
|
49
|
+
end
|
50
|
+
|
51
|
+
def post_codes
|
52
|
+
list_api_client.post_codes
|
53
|
+
end
|
54
|
+
|
55
|
+
def services
|
56
|
+
list_api_client.services
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_mode?
|
60
|
+
@test_mode
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def rest_api_client
|
66
|
+
@rest_api_client ||= RestApiClient.new @login, @password, test_mode: test_mode?
|
67
|
+
end
|
68
|
+
|
69
|
+
def list_api_client
|
70
|
+
@list_api_client ||= ListApiClient.new @login, @password
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ImlClient
|
2
|
+
|
3
|
+
class Error < StandardError
|
4
|
+
|
5
|
+
attr_reader :code, :message
|
6
|
+
|
7
|
+
def initialize(code, message)
|
8
|
+
@code = code
|
9
|
+
@message = message
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
class ResponseError < Error; end
|
15
|
+
|
16
|
+
class APIError < Error; end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'iml_client/abstract_api_client'
|
2
|
+
require 'iml_client/util'
|
3
|
+
|
4
|
+
module ImlClient
|
5
|
+
class ListApiClient < AbstractApiClient
|
6
|
+
|
7
|
+
def initialize(login, password)
|
8
|
+
@login = login
|
9
|
+
@password = password
|
10
|
+
end
|
11
|
+
|
12
|
+
def locations(params = {})
|
13
|
+
result = request_and_normalize url_for(:locations), :get, nil, nil, response_normalization_rules_for(:locations), []
|
14
|
+
unless params[:IncludeNotOpened]
|
15
|
+
result.data.select!{ |d| !d[:OpeningDate].is_a?(Date) || d[:OpeningDate] <= Date.today }
|
16
|
+
end
|
17
|
+
unless params[:IncludeClosed]
|
18
|
+
result.data.select!{ |d| !d[:ClosingDate].is_a?(Date) || d[:ClosingDate] > Date.today }
|
19
|
+
end
|
20
|
+
result
|
21
|
+
end
|
22
|
+
|
23
|
+
def exception_service_regions(params = {})
|
24
|
+
result = request_and_normalize url_for(:exception_service_regions), :get, nil, nil, response_normalization_rules_for(:exception_service_regions), []
|
25
|
+
unless params[:IncludeNotOpened]
|
26
|
+
result.data.select!{ |d| !d[:Open].is_a?(Date) || d[:Open] <= Date.today }
|
27
|
+
end
|
28
|
+
unless params[:IncludeEnded]
|
29
|
+
result.data.select!{ |d| !d[:End].is_a?(Date) || d[:End] > Date.today }
|
30
|
+
end
|
31
|
+
result
|
32
|
+
end
|
33
|
+
|
34
|
+
def regions
|
35
|
+
request_and_normalize url_for(:regions), :get, nil, nil, response_normalization_rules_for(:regions), []
|
36
|
+
end
|
37
|
+
|
38
|
+
def pickup_points(params = {})
|
39
|
+
region_code = params[:RegionCode]
|
40
|
+
method = Util.blank?(region_code) ? :get : :post
|
41
|
+
result = request_and_normalize url_for(:pickup_points), method, nil, region_code, response_normalization_rules_for(:pickup_points), []
|
42
|
+
unless params[:IncludeNotOpened]
|
43
|
+
result.data.select!{ |d| !d[:OpeningDate].is_a?(Date) || d[:OpeningDate] <= Date.today }
|
44
|
+
end
|
45
|
+
unless params[:IncludeClosed]
|
46
|
+
result.data.select!{ |d| !d[:ClosingDate].is_a?(Date) || d[:ClosingDate] > Date.today }
|
47
|
+
end
|
48
|
+
result
|
49
|
+
end
|
50
|
+
|
51
|
+
def status_types
|
52
|
+
request_and_normalize url_for(:status_types), :get, nil, nil, response_normalization_rules_for(:status_types), []
|
53
|
+
end
|
54
|
+
|
55
|
+
def post_codes
|
56
|
+
request_and_normalize url_for(:post_codes), :get, nil, nil, response_normalization_rules_for(:post_codes), []
|
57
|
+
end
|
58
|
+
|
59
|
+
def services
|
60
|
+
request_and_normalize url_for(:services), :get, nil, nil, response_normalization_rules_for(:services), []
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def host
|
66
|
+
ImlClient::LIST_API_HOST
|
67
|
+
end
|
68
|
+
|
69
|
+
def request(url, method, request_params, params)
|
70
|
+
request_params ||= {}
|
71
|
+
request_params[:headers] ||= {}
|
72
|
+
request_params[:headers]['Content-Type'] = 'application/json'
|
73
|
+
request_params[:basic_auth] = { username: @login, password: @password }
|
74
|
+
|
75
|
+
raw_request url, method, request_params, params
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'iml_client/abstract_api_client'
|
2
|
+
require 'iml_client/errors'
|
3
|
+
require 'iml_client/util'
|
4
|
+
|
5
|
+
module ImlClient
|
6
|
+
class RestApiClient < AbstractApiClient
|
7
|
+
|
8
|
+
def initialize(login, password, options = {})
|
9
|
+
@login = login
|
10
|
+
@password = password
|
11
|
+
options = Util.symbolize_keys options
|
12
|
+
@test_mode = !!options[:test_mode]
|
13
|
+
end
|
14
|
+
|
15
|
+
def orders(params = {})
|
16
|
+
request_and_normalize url_for(:orders), :post, nil, params, response_normalization_rules_for(:orders), []
|
17
|
+
end
|
18
|
+
|
19
|
+
def order_statuses(params = {})
|
20
|
+
request_and_normalize url_for(:order_statuses), :post, nil, params, response_normalization_rules_for(:order_statuses), []
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_order(params)
|
24
|
+
result = request url_for(:create_order), :post, nil, params
|
25
|
+
if result.errors.any?
|
26
|
+
result.set_data({})
|
27
|
+
elsif result.data['Result'] == 'Error'
|
28
|
+
result.data['Errors'].each do |error_data|
|
29
|
+
error = ImlClient::APIError.new error_data['Code'], error_data['Message']
|
30
|
+
result.add_error error
|
31
|
+
end
|
32
|
+
result.set_data({})
|
33
|
+
else
|
34
|
+
normalized_data = normalize_response_data result.data['Order'], response_normalization_rules_for(:create_order)
|
35
|
+
result.set_data normalized_data
|
36
|
+
end
|
37
|
+
result
|
38
|
+
end
|
39
|
+
|
40
|
+
def calculate_price(params)
|
41
|
+
result = request url_for(:calculate_price), :post, nil, params
|
42
|
+
if result.errors.any?
|
43
|
+
result.set_data nil
|
44
|
+
elsif !result.data.is_a?(Hash) || result.data['Price'].nil?
|
45
|
+
Util.array_wrap(result.data).each do |error_data|
|
46
|
+
error = ImlClient::APIError.new error_data['Code'], error_data['Mess']
|
47
|
+
result.add_error error
|
48
|
+
end
|
49
|
+
result.set_data nil
|
50
|
+
else
|
51
|
+
result.set_data result.data['Price']
|
52
|
+
end
|
53
|
+
result
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_mode?
|
57
|
+
@test_mode
|
58
|
+
end
|
59
|
+
|
60
|
+
protected
|
61
|
+
|
62
|
+
def host
|
63
|
+
ImlClient::REST_API_HOST
|
64
|
+
end
|
65
|
+
|
66
|
+
def request(url, method, request_params, params)
|
67
|
+
request_params ||= {}
|
68
|
+
request_params[:headers] ||= {}
|
69
|
+
request_params[:headers]['Content-Type'] = 'application/json'
|
70
|
+
request_params[:basic_auth] = { username: @login, password: @password }
|
71
|
+
|
72
|
+
params = normalize_request_data params
|
73
|
+
params[:Test] = test_mode? ? 'True' : 'False'
|
74
|
+
|
75
|
+
raw_request url, method, request_params, params
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ImlClient
|
2
|
+
class Result
|
3
|
+
|
4
|
+
attr_reader :response, :data, :errors
|
5
|
+
|
6
|
+
def initialize(response, data, errors = [])
|
7
|
+
@response = response
|
8
|
+
@data = data
|
9
|
+
@errors = errors
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_data(data)
|
13
|
+
@data = data
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_error(error)
|
17
|
+
errors.push error
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ImlClient
|
2
|
+
module Util
|
3
|
+
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def symbolize_keys(hash)
|
7
|
+
result = {}
|
8
|
+
hash.each do |key, value|
|
9
|
+
result[key.to_sym] = value
|
10
|
+
end
|
11
|
+
result
|
12
|
+
end
|
13
|
+
|
14
|
+
def hash_value_at_keypath(hash, keypath)
|
15
|
+
if keypath.length == 0 || !hash.is_a?(Hash)
|
16
|
+
return nil
|
17
|
+
elsif keypath.length == 1
|
18
|
+
return hash[keypath[0]]
|
19
|
+
else
|
20
|
+
return hash_value_at_keypath hash[keypath[0]], keypath[1..-1]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def blank?(value)
|
25
|
+
value.nil? ||
|
26
|
+
(value.is_a?(String) && value.strip == '') ||
|
27
|
+
((value.is_a?(Array) || (value.is_a?(Hash))) && value.empty?)
|
28
|
+
end
|
29
|
+
|
30
|
+
def array_wrap(value)
|
31
|
+
if value.is_a? Array
|
32
|
+
return value
|
33
|
+
elsif value.nil?
|
34
|
+
return []
|
35
|
+
else
|
36
|
+
return [value]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iml_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Babur Usenakunov
|
@@ -14,16 +14,16 @@ dependencies:
|
|
14
14
|
name: httparty
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: '0.11'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: '0.11'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,7 +44,22 @@ email:
|
|
44
44
|
executables: []
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
|
-
files:
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- Gemfile
|
50
|
+
- LICENSE.txt
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
53
|
+
- iml_client.gemspec
|
54
|
+
- lib/iml_client.rb
|
55
|
+
- lib/iml_client/abstract_api_client.rb
|
56
|
+
- lib/iml_client/client.rb
|
57
|
+
- lib/iml_client/errors.rb
|
58
|
+
- lib/iml_client/list_api_client.rb
|
59
|
+
- lib/iml_client/rest_api_client.rb
|
60
|
+
- lib/iml_client/result.rb
|
61
|
+
- lib/iml_client/util.rb
|
62
|
+
- lib/iml_client/version.rb
|
48
63
|
homepage: https://github.com/bob-frost/iml_client
|
49
64
|
licenses:
|
50
65
|
- MIT
|