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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +23 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +210 -0
  8. data/Rakefile +1 -0
  9. data/lib/seko/client.rb +236 -0
  10. data/lib/seko/company.rb +33 -0
  11. data/lib/seko/dispatch.rb +22 -0
  12. data/lib/seko/filter.rb +9 -0
  13. data/lib/seko/order.rb +77 -0
  14. data/lib/seko/product.rb +27 -0
  15. data/lib/seko/receipt.rb +36 -0
  16. data/lib/seko/response.rb +33 -0
  17. data/lib/seko/shipping.rb +26 -0
  18. data/lib/seko/stock.rb +9 -0
  19. data/lib/seko/tracking.rb +22 -0
  20. data/lib/seko/version.rb +3 -0
  21. data/lib/seko.rb +31 -0
  22. data/seko.gemspec +27 -0
  23. data/spec/fixtures/company_submit.json +21 -0
  24. data/spec/fixtures/dispatch_statuses.json +25 -0
  25. data/spec/fixtures/grn.json +45 -0
  26. data/spec/fixtures/order_status.json +11 -0
  27. data/spec/fixtures/order_submit.json +33 -0
  28. data/spec/fixtures/order_tracking.json +12 -0
  29. data/spec/fixtures/order_websubmit.json +29 -0
  30. data/spec/fixtures/product_submit.json +15 -0
  31. data/spec/fixtures/receipt_submit.json +26 -0
  32. data/spec/fixtures/stock.json +29 -0
  33. data/spec/fixtures/stock_adjustment.json +7 -0
  34. data/spec/fixtures/stock_movement.json +7 -0
  35. data/spec/lib/client_spec.rb +364 -0
  36. data/spec/lib/company_spec.rb +22 -0
  37. data/spec/lib/dispatch_spec.rb +17 -0
  38. data/spec/lib/filter_spec.rb +12 -0
  39. data/spec/lib/order_spec.rb +60 -0
  40. data/spec/lib/product_spec.rb +23 -0
  41. data/spec/lib/receipt_spec.rb +36 -0
  42. data/spec/lib/response_spec.rb +53 -0
  43. data/spec/lib/stock_spec.rb +12 -0
  44. data/spec/logs/spec.log +0 -0
  45. data/spec/spec_helper.rb +176 -0
  46. 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
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in seko.gemspec
4
+ gemspec
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
+ [![Build Status](https://travis-ci.org/jGRUBBS/seko-ruby-api.svg?branch=master)](https://travis-ci.org/jGRUBBS/seko-ruby-api.svg?branch=master)
4
+ [![Code Climate](https://codeclimate.com/github/jGRUBBS/seko-ruby-api/badges/gpa.svg)](https://codeclimate.com/github/jGRUBBS/seko-ruby-api)
5
+ [![Test Coverage](https://codeclimate.com/github/jGRUBBS/seko-ruby-api/badges/coverage.svg)](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'
@@ -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
@@ -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
@@ -0,0 +1,9 @@
1
+ module Seko
2
+ class Filter
3
+
4
+ def self.parse(text)
5
+ text.gsub('|', '-')
6
+ end
7
+
8
+ end
9
+ end
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
@@ -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