seko 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/.rspec +2 -0
- data/.travis.yml +23 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +210 -0
- data/Rakefile +1 -0
- data/lib/seko/client.rb +236 -0
- data/lib/seko/company.rb +33 -0
- data/lib/seko/dispatch.rb +22 -0
- data/lib/seko/filter.rb +9 -0
- data/lib/seko/order.rb +77 -0
- data/lib/seko/product.rb +27 -0
- data/lib/seko/receipt.rb +36 -0
- data/lib/seko/response.rb +33 -0
- data/lib/seko/shipping.rb +26 -0
- data/lib/seko/stock.rb +9 -0
- data/lib/seko/tracking.rb +22 -0
- data/lib/seko/version.rb +3 -0
- data/lib/seko.rb +31 -0
- data/seko.gemspec +27 -0
- data/spec/fixtures/company_submit.json +21 -0
- data/spec/fixtures/dispatch_statuses.json +25 -0
- data/spec/fixtures/grn.json +45 -0
- data/spec/fixtures/order_status.json +11 -0
- data/spec/fixtures/order_submit.json +33 -0
- data/spec/fixtures/order_tracking.json +12 -0
- data/spec/fixtures/order_websubmit.json +29 -0
- data/spec/fixtures/product_submit.json +15 -0
- data/spec/fixtures/receipt_submit.json +26 -0
- data/spec/fixtures/stock.json +29 -0
- data/spec/fixtures/stock_adjustment.json +7 -0
- data/spec/fixtures/stock_movement.json +7 -0
- data/spec/lib/client_spec.rb +364 -0
- data/spec/lib/company_spec.rb +22 -0
- data/spec/lib/dispatch_spec.rb +17 -0
- data/spec/lib/filter_spec.rb +12 -0
- data/spec/lib/order_spec.rb +60 -0
- data/spec/lib/product_spec.rb +23 -0
- data/spec/lib/receipt_spec.rb +36 -0
- data/spec/lib/response_spec.rb +53 -0
- data/spec/lib/stock_spec.rb +12 -0
- data/spec/logs/spec.log +0 -0
- data/spec/spec_helper.rb +176 -0
- metadata +196 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7ccf252a5f73196d16afac7f326d8fca9163f7dc
|
4
|
+
data.tar.gz: 2fb7c168442260f3b587d28e7823fb497bc98254
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1bd565235abd405f4f44d2bf98a1942770ca3b4252ddffd0d83affd78db0d0a1680de9661f0df2f6a2e19d7c5d820e2b9f25f062d9fa5fc9b1cc2f90b3146d3b
|
7
|
+
data.tar.gz: eafb4f39d5629a62b5554b09cbdf8678a810c1f65129693e0a95d1ec4f0312394e6cc9e42e9a617f814b8629651404c69c91f1654f0ed6338077385a28eaa336
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.0.0
|
4
|
+
|
5
|
+
matrix:
|
6
|
+
allow_failures:
|
7
|
+
- rvm: rbx-19mode
|
8
|
+
|
9
|
+
script:
|
10
|
+
- CODECLIMATE_REPO_TOKEN=dd4351c1e437fe6bb682de8e30eae582e627b4e0959ed3202839ad057af5d4d1 bundle exec rspec
|
11
|
+
|
12
|
+
# addons:
|
13
|
+
# code_climate:
|
14
|
+
# repo_token: dd4351c1e437fe6bb682de8e30eae582e627b4e0959ed3202839ad057af5d4d1
|
15
|
+
|
16
|
+
notifications:
|
17
|
+
email:
|
18
|
+
- justin@jgrubbs.net
|
19
|
+
|
20
|
+
gemfile:
|
21
|
+
- Gemfile
|
22
|
+
|
23
|
+
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Justin Grubbs
|
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,210 @@
|
|
1
|
+
# Seko
|
2
|
+
|
3
|
+
[](https://travis-ci.org/jGRUBBS/seko-ruby-api.svg?branch=master)
|
4
|
+
[](https://codeclimate.com/github/jGRUBBS/seko-ruby-api)
|
5
|
+
[](https://codeclimate.com/github/jGRUBBS/seko-ruby-api)
|
6
|
+
|
7
|
+
Ruby wrapper for Seko Logistics' SupplyStream iHub REST API v1
|
8
|
+
|
9
|
+
[SupplyStream REST API Documentation](https://wiki.supplystream.com/GetFile.aspx?Page=MANUAL.Integration-Hub-Rest-APIs&File=integration-ihub-rest-apis-v1.4.pdf)
|
10
|
+
|
11
|
+
## Integrations
|
12
|
+
|
13
|
+
1. **Inbound Product Master Upload and method**
|
14
|
+
2. **Inbound Companies Upload and method**
|
15
|
+
3. **Inbound Advanced Shipment Notification**
|
16
|
+
4. **Inbound Sales Order / Cancel Orders**
|
17
|
+
5. **Retrieve GRN’s**
|
18
|
+
6. **Retrieve Stock Quantity**
|
19
|
+
7. **Retrieve Tracking Details**
|
20
|
+
8. **Retrieve Sales Order Status**
|
21
|
+
9. **Retrieve Stock Adjustments**
|
22
|
+
10. **Retrieve Stock Movements**
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Add this line to your application's Gemfile:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
gem 'seko'
|
30
|
+
```
|
31
|
+
|
32
|
+
And then execute:
|
33
|
+
|
34
|
+
$ bundle
|
35
|
+
|
36
|
+
Or install it yourself as:
|
37
|
+
|
38
|
+
$ gem install seko
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
#### Configuration
|
42
|
+
config/initializers/seko.rb
|
43
|
+
```ruby
|
44
|
+
Seko.configure(
|
45
|
+
token: 'SekoAPIToKeN'
|
46
|
+
supplier_code: 'DEFSUPLJLTD001',
|
47
|
+
supplier_description: 'Default Supplier LARSSON & JENNINGS LTD',
|
48
|
+
supplier_uom: 1,
|
49
|
+
warehouses: {
|
50
|
+
us: 'US123',
|
51
|
+
uk: 'UK123'
|
52
|
+
}
|
53
|
+
)
|
54
|
+
```
|
55
|
+
|
56
|
+
#### Submit Product
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
client = Seko::Client.new(Seko.config[:token])
|
60
|
+
response = client.submit_product(upc: "123456", description: 'A test product')
|
61
|
+
```
|
62
|
+
|
63
|
+
#### Submit Receipt
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
line_items = [ { upc: "123456", quantity: 10 } ]
|
67
|
+
warehouse = Seko.config[:warehouses][:us]
|
68
|
+
client = Seko::Client.new(Seko.config[:token])
|
69
|
+
response = client.submit_receipt(line_item_array, warehouse)
|
70
|
+
```
|
71
|
+
|
72
|
+
#### Submit Company
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
company_hash = {
|
76
|
+
code: 'IND001',
|
77
|
+
description: 'Indigina'
|
78
|
+
}
|
79
|
+
client = Seko::Client.new(Seko.config[:token])
|
80
|
+
response = client.submit_company(company_hash)
|
81
|
+
```
|
82
|
+
|
83
|
+
#### Get Stock
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
client = Seko::Client.new(Seko.config[:token])
|
87
|
+
response = client.get_inventory
|
88
|
+
```
|
89
|
+
|
90
|
+
#### Check GRN
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
client = Seko::Client.new(Seko.config[:token])
|
94
|
+
response = client.check_grn('5b2dcd8e-52c3-4e27-a712-eaacda2dd8fe')
|
95
|
+
```
|
96
|
+
|
97
|
+
#### Order Status
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
client = Seko::Client.new(Seko.config[:token])
|
101
|
+
response = client.order_status('5b2dcd8e-52c3-4e27-a712-eaacda2dd8fe')
|
102
|
+
```
|
103
|
+
|
104
|
+
#### Order Tracking
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
client = Seko::Client.new(Seko.config[:token])
|
108
|
+
response = client.order_tracking('5b2dcd8e-52c3-4e27-a712-eaacda2dd8fe')
|
109
|
+
```
|
110
|
+
|
111
|
+
#### Cancel Order
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
Seko::Order::CANCEL_CODES
|
115
|
+
# => {
|
116
|
+
# "001" => "Customer Request",
|
117
|
+
# "002" => "Order Delayed",
|
118
|
+
# "003" => "Duplicate",
|
119
|
+
# "004" => "Item not available",
|
120
|
+
# "005" => "Cannot ship to address",
|
121
|
+
# "006" => "Other"
|
122
|
+
# }
|
123
|
+
|
124
|
+
client = Seko::Client.new(Seko.config[:token])
|
125
|
+
response = client.cancel_order('5b2dcd8e-52c3-4e27-a712-eaacda2dd8fe', '001')
|
126
|
+
```
|
127
|
+
|
128
|
+
#### Stock Movements
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
client = Seko::Client.new(Seko.config[:token])
|
132
|
+
warehouse = Seko.config[:warehouses][:us]
|
133
|
+
from = 3.days.ago
|
134
|
+
to = Time.now
|
135
|
+
response = client.stock_movements(from, to, warehouse)
|
136
|
+
```
|
137
|
+
|
138
|
+
#### Stock Adjustments
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
client = Seko::Client.new(Seko.config[:token])
|
142
|
+
warehouse = Seko.config[:warehouses][:us]
|
143
|
+
from = 3.days.ago
|
144
|
+
to = Time.now
|
145
|
+
response = client.stock_adjustments(from, to, warehouse)
|
146
|
+
```
|
147
|
+
|
148
|
+
#### Dispatch Statuses
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
client = Seko::Client.new(Seko.config[:token])
|
152
|
+
warehouse = Seko.config[:warehouses][:us] # warehouse is optional
|
153
|
+
from = 3.days.ago
|
154
|
+
to = Time.now
|
155
|
+
response = client.dispatch_statuses(from, to, warehouse)
|
156
|
+
|
157
|
+
# get collection of GUIDs dispatched
|
158
|
+
guid_array = Seko::Dispatch.parse(response)
|
159
|
+
# returns something like this
|
160
|
+
# => ["2b5e52cc-fb6f-4ea4-b8cf-cf64e3a2b8db", "93e92ca2-725a-46f8-90dd-43a16105f78d"]
|
161
|
+
```
|
162
|
+
|
163
|
+
#### Submit Order
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
order = {
|
167
|
+
shipping_address: {
|
168
|
+
first_name: "John",
|
169
|
+
last_name: "Smith",
|
170
|
+
address1: "123 Here Now",
|
171
|
+
address2: "2nd Floor",
|
172
|
+
city: "New York",
|
173
|
+
state: "New York",
|
174
|
+
country: "US",
|
175
|
+
zipcode: "10012",
|
176
|
+
phone: "123-123-1234"
|
177
|
+
},
|
178
|
+
email: "someone@somehwere.com",
|
179
|
+
number: "R123123123",
|
180
|
+
warehouse: "DC123",
|
181
|
+
date: "2013-12-12",
|
182
|
+
line_items: [
|
183
|
+
{
|
184
|
+
quantity: "1",
|
185
|
+
sku: "123332211"
|
186
|
+
}
|
187
|
+
]
|
188
|
+
}
|
189
|
+
|
190
|
+
client = Seko::Client.new(Seko.config[:token])
|
191
|
+
response = client.send_order_request(order)
|
192
|
+
|
193
|
+
### NOTE you may want to store the GUID from the response
|
194
|
+
### you need the guid for status updates, tracking, and canceling orders
|
195
|
+
response.guid
|
196
|
+
|
197
|
+
if response.success?
|
198
|
+
# DO SOMETHING
|
199
|
+
else
|
200
|
+
# QUEUE REQUEST, STORE AND RAISE ERRORS
|
201
|
+
end
|
202
|
+
```
|
203
|
+
|
204
|
+
## Contributing
|
205
|
+
|
206
|
+
1. Fork it ( https://github.com/[my-github-username]/seko/fork )
|
207
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
208
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
209
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
210
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/lib/seko/client.rb
ADDED
@@ -0,0 +1,236 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Seko
|
5
|
+
class Client
|
6
|
+
|
7
|
+
PORT = 443
|
8
|
+
TEST_HOST = 'hubuat1.supplystream.com'
|
9
|
+
# api.supplystream.com
|
10
|
+
LIVE_HOST = 'hub.supplystream.com'
|
11
|
+
API_PATH = '/hub/api/'
|
12
|
+
API_VERSION = 'v1'
|
13
|
+
CONTENT_TYPE = 'application/json'
|
14
|
+
KEYS_MAP = {
|
15
|
+
"FreeQuantity" => "qty",
|
16
|
+
"ProductCode" => "upc"
|
17
|
+
}
|
18
|
+
|
19
|
+
attr_accessor :token, :response, :type, :request_uri, :path, :service, :endpoint, :options
|
20
|
+
|
21
|
+
def initialize(token, options = {})
|
22
|
+
raise "Token is required" unless token
|
23
|
+
|
24
|
+
@token = token
|
25
|
+
@options = default_options.merge(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def send_order_request(order_hash)
|
29
|
+
@service = 'salesorders'
|
30
|
+
@endpoint = 'websubmit'
|
31
|
+
post(Order.websubmit(order_hash))
|
32
|
+
end
|
33
|
+
|
34
|
+
def order_request(order_hash)
|
35
|
+
Order.websubmit(order_hash).to_json
|
36
|
+
end
|
37
|
+
|
38
|
+
def send_wholesale_request(order_hash)
|
39
|
+
@service = 'salesorders'
|
40
|
+
@endpoint = 'submit'
|
41
|
+
post(Order.submit(order_hash))
|
42
|
+
end
|
43
|
+
|
44
|
+
def wholesale_request(order_hash)
|
45
|
+
Order.submit(order_hash).to_json
|
46
|
+
end
|
47
|
+
|
48
|
+
# FIXME: use this method once SS fixes their API
|
49
|
+
# for now we are manually sorting the distribution centre
|
50
|
+
# see #inventory_response below
|
51
|
+
#
|
52
|
+
# def get_inventory(warehouse = nil)
|
53
|
+
# @service = 'stock'
|
54
|
+
# @endpoint = if warehouse.nil?
|
55
|
+
# "all"
|
56
|
+
# else
|
57
|
+
# "dc/#{warehouse}"
|
58
|
+
# end
|
59
|
+
# inventory_response
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# def inventory_response
|
63
|
+
# response = get
|
64
|
+
# response.parsed = map_results(Stock.parse(response))
|
65
|
+
# response
|
66
|
+
# end
|
67
|
+
|
68
|
+
def get_inventory(warehouse = nil)
|
69
|
+
@service = 'stock'
|
70
|
+
@endpoint = 'all'
|
71
|
+
inventory_response(warehouse)
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def inventory_response(warehouse = nil)
|
76
|
+
response = get
|
77
|
+
response.parsed = map_results(Stock.parse(response)).select do |stock|
|
78
|
+
warehouse.nil? ? true : stock["DCCode"] == warehouse
|
79
|
+
end
|
80
|
+
response
|
81
|
+
end
|
82
|
+
|
83
|
+
def upcs(inventory)
|
84
|
+
inventory.collect { |s| s["upc"] }
|
85
|
+
end
|
86
|
+
|
87
|
+
def mapped_inventory(upcs, inventory)
|
88
|
+
inventory.collect do |stock|
|
89
|
+
if upcs.include?(stock["upc"])
|
90
|
+
{ quantity: stock["qty"].to_i }
|
91
|
+
end
|
92
|
+
end.compact
|
93
|
+
end
|
94
|
+
|
95
|
+
def map_results(results)
|
96
|
+
results.map { |h| h.inject({ }) { |x, (k,v)| x[map_keys(k)] = v; x } }
|
97
|
+
end
|
98
|
+
|
99
|
+
def map_keys(key)
|
100
|
+
KEYS_MAP[key] || key
|
101
|
+
end
|
102
|
+
|
103
|
+
def submit_product(product_hash)
|
104
|
+
@service = 'products'
|
105
|
+
@endpoint = 'submit'
|
106
|
+
post(Product.format(product_hash))
|
107
|
+
end
|
108
|
+
|
109
|
+
def submit_receipt(line_item_array, warehouse)
|
110
|
+
@service = 'receipts'
|
111
|
+
@endpoint = 'submit'
|
112
|
+
post(Receipt.format(line_item_array, warehouse))
|
113
|
+
end
|
114
|
+
|
115
|
+
def submit_company(company_hash)
|
116
|
+
@service = 'companies'
|
117
|
+
@endpoint = 'submit'
|
118
|
+
post(Company.format(company_hash))
|
119
|
+
end
|
120
|
+
|
121
|
+
def check_grn(guid)
|
122
|
+
@service = 'grns'
|
123
|
+
@endpoint = guid
|
124
|
+
get
|
125
|
+
end
|
126
|
+
|
127
|
+
def order_status(guid)
|
128
|
+
@service = 'salesorders'
|
129
|
+
@endpoint = "#{guid}/status"
|
130
|
+
get
|
131
|
+
end
|
132
|
+
|
133
|
+
def order_tracking(guid)
|
134
|
+
@service = 'salesorders'
|
135
|
+
@endpoint = "#{guid}/tracking"
|
136
|
+
get
|
137
|
+
end
|
138
|
+
|
139
|
+
def cancel_order(guid, reason_code)
|
140
|
+
@service = 'salesorders'
|
141
|
+
@endpoint = "#{guid}/cancel/reasoncode/#{reason_code}"
|
142
|
+
post({'Cancel' => 'Order'})
|
143
|
+
end
|
144
|
+
|
145
|
+
def stock_adjustments(from, to, warehouse)
|
146
|
+
@service = 'stock'
|
147
|
+
@endpoint = "adjustment/#{format_from_to(from, to)}"
|
148
|
+
get("#{request_uri}&dc=#{warehouse}")
|
149
|
+
end
|
150
|
+
|
151
|
+
def stock_movements(from, to, warehouse)
|
152
|
+
@service = 'stock'
|
153
|
+
@endpoint = "movement/#{format_from_to(from, to)}"
|
154
|
+
get("#{request_uri}&dc=#{warehouse}")
|
155
|
+
end
|
156
|
+
|
157
|
+
def dispatch_statuses(from, to, warehouse = nil)
|
158
|
+
@service = 'dispatches'
|
159
|
+
@endpoint = "status/#{format_from_to(from, to)}"
|
160
|
+
request_url = "#{request_uri}&status=Dispatched"
|
161
|
+
request_url += "&dc=#{warehouse}" unless warehouse.nil?
|
162
|
+
get(request_url)
|
163
|
+
end
|
164
|
+
|
165
|
+
def request_uri
|
166
|
+
"https://#{host}#{path}?token=#{token}"
|
167
|
+
end
|
168
|
+
|
169
|
+
def path
|
170
|
+
"#{API_PATH}#{service}/#{API_VERSION}/#{endpoint}.json"
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
def default_options
|
175
|
+
{
|
176
|
+
verbose: false,
|
177
|
+
test_mode: true
|
178
|
+
}
|
179
|
+
end
|
180
|
+
|
181
|
+
def testing?
|
182
|
+
@options[:test_mode]
|
183
|
+
end
|
184
|
+
|
185
|
+
def verbose?
|
186
|
+
@options[:verbose]
|
187
|
+
end
|
188
|
+
|
189
|
+
def host
|
190
|
+
testing? ? TEST_HOST : LIVE_HOST
|
191
|
+
end
|
192
|
+
|
193
|
+
def log(message)
|
194
|
+
return unless verbose?
|
195
|
+
puts message
|
196
|
+
end
|
197
|
+
|
198
|
+
def http
|
199
|
+
@http ||= Net::HTTP.new(host, PORT)
|
200
|
+
end
|
201
|
+
|
202
|
+
def build_request(type, url = request_uri)
|
203
|
+
request = Net::HTTP.const_get(type).new(url)
|
204
|
+
request.content_type = CONTENT_TYPE
|
205
|
+
request
|
206
|
+
end
|
207
|
+
|
208
|
+
def request(request, json_request = nil)
|
209
|
+
http.use_ssl = true
|
210
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
211
|
+
response = http.request(request)
|
212
|
+
parse_response(response.body)
|
213
|
+
end
|
214
|
+
|
215
|
+
def get(url = request_uri)
|
216
|
+
request = build_request('Get', url)
|
217
|
+
request(request)
|
218
|
+
end
|
219
|
+
|
220
|
+
def post(json_request, url = request_uri)
|
221
|
+
request = build_request('Post', url)
|
222
|
+
request.body = json_request.to_json
|
223
|
+
request(request)
|
224
|
+
end
|
225
|
+
|
226
|
+
def parse_response(json_response)
|
227
|
+
log(json_response)
|
228
|
+
@response = Response.new(json_response)
|
229
|
+
end
|
230
|
+
|
231
|
+
def format_from_to(from, to)
|
232
|
+
"#{from.strftime('%F')}T00:00:00Z/#{to.strftime('%F')}T00:00:00Z"
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
end
|
data/lib/seko/company.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Seko
|
2
|
+
class Company
|
3
|
+
|
4
|
+
def self.format(company)
|
5
|
+
{
|
6
|
+
"Request" => {
|
7
|
+
"Company" => {
|
8
|
+
"CompanyCode" => company[:code],
|
9
|
+
"CompanyDescription" => company[:description],
|
10
|
+
"CompanyType" => "Ship To"
|
11
|
+
},
|
12
|
+
"List" => {
|
13
|
+
"Address" => address(company[:address])
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.address(address)
|
20
|
+
{
|
21
|
+
"AddressLine1" => address[:address1],
|
22
|
+
"AddressLine2" => address[:address2],
|
23
|
+
"AddressLine3" => address[:address3],
|
24
|
+
"AddressType" => "Delivery",
|
25
|
+
"City" => address[:city],
|
26
|
+
"CountryCode" => address[:country],
|
27
|
+
"County" => address[:country_name],
|
28
|
+
"PostcodeZip" => address[:zipcode]
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Seko
|
2
|
+
class Dispatch
|
3
|
+
|
4
|
+
def self.line_items(response)
|
5
|
+
response.root_response["List"]["DispatchLineItem"]
|
6
|
+
end
|
7
|
+
|
8
|
+
# returns array of GUIDs
|
9
|
+
def self.parse(response)
|
10
|
+
dispatches = line_items(response)
|
11
|
+
# API is flawed and returns an array if multiple dispatches
|
12
|
+
if dispatches.is_a?(Array)
|
13
|
+
dispatches.collect { |h| h["GUID"] }
|
14
|
+
else
|
15
|
+
# and a singular object otherwise
|
16
|
+
# so we wrap it as an array
|
17
|
+
Array(dispatches["GUID"])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/lib/seko/filter.rb
ADDED
data/lib/seko/order.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
module Seko
|
2
|
+
class Order
|
3
|
+
|
4
|
+
CANCEL_CODES = {
|
5
|
+
'001' => 'Customer Request',
|
6
|
+
'002' => 'Order Delayed',
|
7
|
+
'003' => 'Duplicate',
|
8
|
+
'004' => 'Item not available',
|
9
|
+
'005' => 'Cannot ship to address',
|
10
|
+
'006' => 'Other'
|
11
|
+
}
|
12
|
+
|
13
|
+
def self.websubmit(attributes)
|
14
|
+
build_request(attributes, "Web")
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.submit(attributes)
|
18
|
+
build_request(attributes)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.build_request(attributes, type = nil)
|
22
|
+
formatted = format(attributes, type)
|
23
|
+
formatted["Request"].merge!(company(attributes[:company])) if attributes[:company]
|
24
|
+
formatted
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.format(order, order_prefix = nil)
|
28
|
+
{
|
29
|
+
"Request" => {
|
30
|
+
"DeliveryDetails" => address(order[:shipping_address], order[:email]),
|
31
|
+
"List" => {
|
32
|
+
"SalesOrderLineItem" => line_items(order[:line_items])
|
33
|
+
},
|
34
|
+
"SalesOrderHeader" => { "DCCode" => order[:warehouse] },
|
35
|
+
"#{order_prefix}SalesOrder" => {
|
36
|
+
"SalesOrderDate" => order[:date],
|
37
|
+
"SalesOrderNumber" => order[:number]
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.address(address, email)
|
44
|
+
{
|
45
|
+
"City" => address[:city],
|
46
|
+
"CountryCode" => address[:country],
|
47
|
+
"EmailAddress" => email,
|
48
|
+
"FirstName" => address[:first_name],
|
49
|
+
"LastName" => address[:last_name],
|
50
|
+
"Line1" => address[:address1],
|
51
|
+
"Line2" => address[:address2],
|
52
|
+
"PhoneNumber" => address[:phone],
|
53
|
+
"PostcodeZip" => address[:zipcode]
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.line_items(items)
|
58
|
+
items.collect.with_index do |line_item, index|
|
59
|
+
{
|
60
|
+
"LineNumber" => index + 1,
|
61
|
+
"ProductCode" => line_item[:sku],
|
62
|
+
"Quantity" => line_item[:quantity]
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.company(company)
|
68
|
+
{
|
69
|
+
"ShipToCompany" => {
|
70
|
+
"CompanyCode" => company[:code],
|
71
|
+
"CompanyDescription" => company[:description]
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
data/lib/seko/product.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Seko
|
2
|
+
class Product
|
3
|
+
|
4
|
+
def self.supplier
|
5
|
+
{
|
6
|
+
"SupplierCode" => Seko.config[:supplier_code],
|
7
|
+
"SupplierDescription" => Seko.config[:supplier_description],
|
8
|
+
"UOM" => Seko.config[:supplier_uom]
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.format(attributes)
|
13
|
+
{
|
14
|
+
"Request" => {
|
15
|
+
"List" => {
|
16
|
+
"SupplierMapping" => supplier
|
17
|
+
},
|
18
|
+
"ProductMaster" => {
|
19
|
+
"ProductCode" => attributes[:upc],
|
20
|
+
"ProductDescription" => Filter.parse(attributes[:description])
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|