ecwid_api 0.0.2 → 0.1.0
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 +4 -4
- data/.travis.yml +8 -0
- data/Gemfile +2 -0
- data/README.md +228 -144
- data/ecwid_api.gemspec +1 -0
- data/lib/ecwid_api/api/base.rb +17 -0
- data/lib/ecwid_api/api/categories.rb +57 -0
- data/lib/ecwid_api/api/orders.rb +36 -0
- data/lib/ecwid_api/api/product_combinations.rb +51 -0
- data/lib/ecwid_api/api/products.rb +64 -0
- data/lib/ecwid_api/api.rb +31 -0
- data/lib/ecwid_api/category.rb +59 -4
- data/lib/ecwid_api/client.rb +65 -94
- data/lib/ecwid_api/entity.rb +138 -26
- data/lib/ecwid_api/error.rb +12 -2
- data/lib/ecwid_api/o_auth.rb +106 -0
- data/lib/ecwid_api/order.rb +82 -0
- data/lib/ecwid_api/order_item.rb +17 -0
- data/lib/ecwid_api/paged_ecwid_response.rb +55 -0
- data/lib/ecwid_api/paged_enumerator.rb +66 -0
- data/lib/ecwid_api/person.rb +7 -0
- data/lib/ecwid_api/product.rb +77 -0
- data/lib/ecwid_api/product_combination.rb +34 -0
- data/lib/ecwid_api/version.rb +1 -1
- data/lib/ecwid_api.rb +25 -39
- data/lib/ext/string.rb +12 -4
- data/spec/api/categories_spec.rb +31 -0
- data/spec/api/orders_spec.rb +30 -0
- data/spec/api/products_spec.rb +20 -0
- data/spec/category_spec.rb +33 -38
- data/spec/client_spec.rb +20 -48
- data/spec/entity_spec.rb +90 -5
- data/spec/fixtures/categories.json +28 -22
- data/spec/fixtures/order.json +162 -0
- data/spec/fixtures/orders.json +302 -0
- data/spec/fixtures/products.json +141 -0
- data/spec/helpers/client.rb +32 -0
- data/spec/oauth_spec.rb +40 -0
- data/spec/order_item_spec.rb +12 -0
- data/spec/order_spec.rb +71 -0
- data/spec/paged_enumerator_spec.rb +38 -0
- data/spec/spec_helper.rb +24 -23
- metadata +53 -9
- data/lib/ecwid_api/category_api.rb +0 -62
- data/spec/category_api_spec.rb +0 -36
- data/spec/ecwid_api_spec.rb +0 -15
- data/spec/helpers/faraday.rb +0 -30
@@ -0,0 +1,31 @@
|
|
1
|
+
module EcwidApi
|
2
|
+
# Internal: A base class for common API functionality
|
3
|
+
module Api
|
4
|
+
autoload :Base, "ecwid_api/api/base"
|
5
|
+
autoload :Orders, "ecwid_api/api/orders"
|
6
|
+
autoload :Products, "ecwid_api/api/products"
|
7
|
+
autoload :Categories, "ecwid_api/api/categories"
|
8
|
+
autoload :ProductCombinations, "ecwid_api/api/product_combinations"
|
9
|
+
|
10
|
+
# Private: Gets the Client
|
11
|
+
attr_reader :client
|
12
|
+
private :client
|
13
|
+
|
14
|
+
# Private: Raises an Error if a request failed, otherwise it will
|
15
|
+
# yield the block
|
16
|
+
#
|
17
|
+
# response - a Faraday::Response object
|
18
|
+
#
|
19
|
+
# Yield if the response was successful
|
20
|
+
#
|
21
|
+
# Raises an error with the status code and reason if the response failed
|
22
|
+
#
|
23
|
+
def raise_on_failure(response)
|
24
|
+
if response.success?
|
25
|
+
yield(response) if block_given?
|
26
|
+
else
|
27
|
+
raise ResponseError.new(response)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/ecwid_api/category.rb
CHANGED
@@ -1,14 +1,69 @@
|
|
1
|
+
require "open-uri"
|
2
|
+
|
1
3
|
module EcwidApi
|
2
4
|
class Category < Entity
|
5
|
+
self.url_root = "categories"
|
6
|
+
|
7
|
+
ecwid_reader :id, :parentId, :orderBy, :thumbnailUrl, :originalImageUrl,
|
8
|
+
:name, :url, :productCount, :description, :enabled, :productIds
|
9
|
+
|
10
|
+
ecwid_writer :name, :parentId, :orderBy, :description, :enabled, :productIds
|
11
|
+
|
3
12
|
# Public: Returns an Array of sub categories for the Category
|
4
|
-
def sub_categories
|
5
|
-
@sub_categories ||= client.categories.all(id)
|
13
|
+
def sub_categories(params = {})
|
14
|
+
@sub_categories ||= client.categories.all(params.merge(parent: id))
|
15
|
+
end
|
16
|
+
|
17
|
+
# Public: Returns an Array of all of the sub categories (deep) for the
|
18
|
+
# Category
|
19
|
+
def all_sub_categories(params = {})
|
20
|
+
@all_sub_categories ||= sub_categories(params) + sub_categories.flat_map do |sub|
|
21
|
+
sub.all_sub_categories(params)
|
22
|
+
end
|
6
23
|
end
|
7
24
|
|
8
25
|
# Public: Returns the parent EcwidApi::Category, or nil if there isn't one
|
9
26
|
def parent
|
10
|
-
|
11
|
-
|
27
|
+
@parent ||= begin
|
28
|
+
parent_id = data["parentId"]
|
29
|
+
client.categories.find(parent_id) if parent_id
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def parents
|
34
|
+
if parent
|
35
|
+
parent.parents + [parent]
|
36
|
+
else
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Public: Returns the Products that belong to the Category
|
42
|
+
#
|
43
|
+
# params - a Hash of values that can be used for a Prdocut search
|
44
|
+
#
|
45
|
+
# Returns an Enumeration of Products
|
46
|
+
def products(params = {})
|
47
|
+
@products ||= product_ids.map do |product_id|
|
48
|
+
client.products.find(product_id)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def product_ids
|
53
|
+
super || []
|
54
|
+
end
|
55
|
+
|
56
|
+
# Public: Uploads an image for the Category
|
57
|
+
#
|
58
|
+
# filename - a String that is the path to a local file or a URL
|
59
|
+
#
|
60
|
+
# Returns a Faraday::Response object
|
61
|
+
def upload_image!(filename)
|
62
|
+
client.post("categories/#{id}/image") do |req|
|
63
|
+
req.body = open(filename).read
|
64
|
+
end.tap do |response|
|
65
|
+
raise_on_failure(response)
|
66
|
+
end
|
12
67
|
end
|
13
68
|
end
|
14
69
|
end
|
data/lib/ecwid_api/client.rb
CHANGED
@@ -1,95 +1,66 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
# Public:
|
22
|
-
|
23
|
-
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
# # => #<Faraday::Response>
|
67
|
-
#
|
68
|
-
# Returns a Faraday::Response
|
69
|
-
def get(path, params={})
|
70
|
-
connection.get(path, params)
|
71
|
-
end
|
72
|
-
|
73
|
-
# Public: Returns the Category API
|
74
|
-
def categories
|
75
|
-
@categories ||= CategoryApi.new(self)
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
# Private: Resets the connection.
|
81
|
-
#
|
82
|
-
# Should be used if the base URL to the Ecwid API changes
|
83
|
-
def reset_connection
|
84
|
-
@connection = nil
|
85
|
-
end
|
86
|
-
|
87
|
-
# Private: Returns a Faraday connection to interface with the Ecwid API
|
88
|
-
def connection
|
89
|
-
@connection ||= Faraday.new store_url do |conn|
|
90
|
-
conn.response :json, content_type: /\bjson$/
|
91
|
-
conn.adapter Faraday.default_adapter
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
1
|
+
module EcwidApi
|
2
|
+
# Public: Client objects manage the connection and interface to a single Ecwid
|
3
|
+
# store.
|
4
|
+
#
|
5
|
+
# Examples
|
6
|
+
#
|
7
|
+
# client = EcwidApi::Client.new(store_id: '12345', token: 'the access_token')
|
8
|
+
# client.get "/products"
|
9
|
+
#
|
10
|
+
class Client
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
# The default base URL for the Ecwid API
|
14
|
+
DEFAULT_URL = "https://app.ecwid.com/api/v3"
|
15
|
+
|
16
|
+
# Public: Returns the Ecwid Store ID
|
17
|
+
attr_reader :store_id
|
18
|
+
attr_reader :token
|
19
|
+
attr_reader :adapter
|
20
|
+
|
21
|
+
# Public: Initializes a new Client to interact with the API
|
22
|
+
#
|
23
|
+
# store_id - the Ecwid store_id to interact with
|
24
|
+
# token - the authorization token provided by oAuth. See the
|
25
|
+
# Authentication class
|
26
|
+
#
|
27
|
+
def initialize(store_id, token, adapter = Faraday.default_adapter)
|
28
|
+
@store_id, @token, @adapter = store_id, token, adapter
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public: The URL of the API for the Ecwid Store
|
32
|
+
def store_url
|
33
|
+
"#{DEFAULT_URL}/#{store_id}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def_delegators :connection, :get, :post, :put, :delete
|
37
|
+
|
38
|
+
# Public: Returns the Category API
|
39
|
+
def categories
|
40
|
+
@categories ||= Api::Categories.new(self)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Public: Returns the Order API
|
44
|
+
def orders
|
45
|
+
@orders ||= Api::Orders.new(self)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Public: Returns the Products API
|
49
|
+
def products
|
50
|
+
@products ||= Api::Products.new(self)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Private: Returns a Faraday connection to interface with the Ecwid API
|
54
|
+
def connection
|
55
|
+
@connection ||= Faraday.new store_url do |conn|
|
56
|
+
conn.request :oauth2, token, param_name: :token
|
57
|
+
conn.request :json
|
58
|
+
|
59
|
+
conn.response :json, content_type: /\bjson$/
|
60
|
+
conn.response :logger
|
61
|
+
|
62
|
+
conn.adapter adapter
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
95
66
|
end
|
data/lib/ecwid_api/entity.rb
CHANGED
@@ -1,12 +1,86 @@
|
|
1
1
|
module EcwidApi
|
2
2
|
class Entity
|
3
|
-
|
4
|
-
attr_reader :client
|
5
|
-
private :client
|
3
|
+
include Api
|
6
4
|
|
7
5
|
# Private: Gets the Hash of data
|
8
6
|
attr_reader :data
|
9
|
-
|
7
|
+
protected :data
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_accessor :url_root
|
11
|
+
|
12
|
+
def define_accessor(attribute, &block)
|
13
|
+
if const_defined?(:Accessors, false)
|
14
|
+
mod = const_get(:Accessors)
|
15
|
+
else
|
16
|
+
mod = const_set(:Accessors, Module.new)
|
17
|
+
include mod
|
18
|
+
end
|
19
|
+
|
20
|
+
mod.module_eval do
|
21
|
+
define_method(attribute, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private :define_accessor
|
26
|
+
|
27
|
+
# Public: Creates a snake_case access method from an Ecwid property name
|
28
|
+
#
|
29
|
+
# Example
|
30
|
+
#
|
31
|
+
# class Product < Entity
|
32
|
+
# ecwid_reader :id, :inStock
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# product = client.products.find(12)
|
36
|
+
# product.in_stock
|
37
|
+
#
|
38
|
+
def ecwid_reader(*attrs)
|
39
|
+
attrs.map(&:to_s).each do |attribute|
|
40
|
+
method = attribute.underscore
|
41
|
+
define_accessor(method) do
|
42
|
+
self[attribute]
|
43
|
+
end unless method_defined?(attribute.underscore)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Public: Creates a snake_case writer method from an Ecwid property name
|
48
|
+
#
|
49
|
+
# Example
|
50
|
+
#
|
51
|
+
# class Product < Entity
|
52
|
+
# ecwid_writer :inStock
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# product = client.products.find(12)
|
56
|
+
# product.in_stock = true
|
57
|
+
#
|
58
|
+
def ecwid_writer(*attrs)
|
59
|
+
attrs.map(&:to_s).each do |attribute|
|
60
|
+
method = "#{attribute.underscore}="
|
61
|
+
define_accessor(method) do |value|
|
62
|
+
@new_data[attribute] = value
|
63
|
+
end unless method_defined?(method)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Public: Creates a snake_case accessor method from an Ecwid property name
|
68
|
+
#
|
69
|
+
# Example
|
70
|
+
#
|
71
|
+
# class Product < Entity
|
72
|
+
# ecwid_accessor :inStock
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# product = client.products.find(12)
|
76
|
+
# product.in_stock
|
77
|
+
# product.in_stock = true
|
78
|
+
#
|
79
|
+
def ecwid_accessor(*attrs)
|
80
|
+
ecwid_reader(*attrs)
|
81
|
+
ecwid_writer(*attrs)
|
82
|
+
end
|
83
|
+
end
|
10
84
|
|
11
85
|
# Public: Initialize a new entity with a reference to the client and data
|
12
86
|
#
|
@@ -16,6 +90,7 @@ module EcwidApi
|
|
16
90
|
#
|
17
91
|
def initialize(data, opts={})
|
18
92
|
@client, @data = opts[:client], data
|
93
|
+
@new_data = {}
|
19
94
|
end
|
20
95
|
|
21
96
|
# Public: Returns a property of the data (actual property name)
|
@@ -31,37 +106,74 @@ module EcwidApi
|
|
31
106
|
#
|
32
107
|
# Returns the value of the property, or nil if it doesn't exist
|
33
108
|
def [](key)
|
34
|
-
data[key.to_s]
|
109
|
+
@new_data[key.to_s] || data[key.to_s]
|
35
110
|
end
|
36
111
|
|
37
|
-
# Public:
|
38
|
-
#
|
39
|
-
# This is used as a helper to allow easy access to the data. It will work
|
40
|
-
# with both CamelCased and snake_case keys. For example, if the data
|
41
|
-
# contains a "parentId" key, then calling `entity.parent_id` should work.
|
42
|
-
#
|
43
|
-
# This will NOT return null of the property doesn't exist on the data!
|
112
|
+
# Public: The URL of the entity
|
44
113
|
#
|
45
|
-
#
|
114
|
+
# Returns a String that is the URL of the entity
|
115
|
+
def url
|
116
|
+
url_root = self.class.url_root
|
117
|
+
raise Error.new("Please specify a url_root for the #{self.class.to_s}") unless url_root
|
118
|
+
|
119
|
+
if url_root.respond_to?(:call)
|
120
|
+
url_root = instance_exec(&url_root)
|
121
|
+
end
|
122
|
+
|
123
|
+
url_root + "/#{id}"
|
124
|
+
end
|
125
|
+
|
126
|
+
def assign_attributes(attributes)
|
127
|
+
attributes.each do |key, val|
|
128
|
+
send("#{key}=", val)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def assign_raw_attributes(attributes)
|
133
|
+
attributes.each do |key, val|
|
134
|
+
@new_data[key.to_s] = val
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def update_attributes(attributes)
|
139
|
+
assign_attributes(attributes)
|
140
|
+
save
|
141
|
+
end
|
142
|
+
|
143
|
+
def update_raw_attributes(attributes)
|
144
|
+
assign_raw_attributes(attributes)
|
145
|
+
save
|
146
|
+
end
|
147
|
+
|
148
|
+
# Public: Saves the Entity
|
46
149
|
#
|
47
|
-
#
|
150
|
+
# Saves anything stored in the @new_data hash
|
48
151
|
#
|
49
|
-
#
|
50
|
-
# return a property if it doesn't have a null value. An example of this are
|
51
|
-
# the top level categories. They don't have a parentId, so that property
|
52
|
-
# is ommitted from the API response. Calling `category.parent_id` will
|
53
|
-
# result in an "undefined method `parent_id'". However, calling `#parent_id`
|
54
|
-
# on any other category will work.
|
152
|
+
# path - the URL of the entity
|
55
153
|
#
|
56
|
-
|
57
|
-
|
58
|
-
|
154
|
+
def save
|
155
|
+
unless @new_data.empty?
|
156
|
+
client.put(url, @new_data).tap do |response|
|
157
|
+
raise_on_failure(response)
|
158
|
+
@data.merge!(@new_data)
|
159
|
+
@new_data.clear
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
59
163
|
|
60
|
-
|
61
|
-
|
164
|
+
# Public: Destroys the Entity
|
165
|
+
def destroy!
|
166
|
+
client.delete(url).tap do |response|
|
167
|
+
raise_on_failure(response)
|
62
168
|
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def to_hash
|
172
|
+
data
|
173
|
+
end
|
63
174
|
|
64
|
-
|
175
|
+
def to_json(*args)
|
176
|
+
data.to_json(*args)
|
65
177
|
end
|
66
178
|
end
|
67
179
|
end
|
data/lib/ecwid_api/error.rb
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
-
module EcwidApi
|
2
|
-
class Error < StandardError; end;
|
1
|
+
module EcwidApi
|
2
|
+
class Error < StandardError; end;
|
3
|
+
|
4
|
+
class ResponseError < Error
|
5
|
+
def initialize(response)
|
6
|
+
if response.respond_to?(:reason_phrase)
|
7
|
+
super("#{response.reason_phrase} (#{response.status})")
|
8
|
+
else
|
9
|
+
super "The Ecwid API responded with an error (#{response.status})"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
3
13
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "ostruct"
|
3
|
+
|
4
|
+
module EcwidApi
|
5
|
+
# Public: Authentication objects manage OAuth authentication with an Ecwid
|
6
|
+
# store.
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
#
|
10
|
+
# app = EcwidApi::Authentication.new do |config|
|
11
|
+
# # see initialize for configuration
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# app.oauth_url # send the user here to authorize the app
|
15
|
+
#
|
16
|
+
# token = app.access_token(params[:code]) # this is the code they provide
|
17
|
+
# # to the redirect_uri
|
18
|
+
# token.access_token
|
19
|
+
# token.store_id # these are what you need to access the API
|
20
|
+
#
|
21
|
+
class OAuth
|
22
|
+
CONFIG = %w(client_id client_secret scope redirect_uri)
|
23
|
+
attr_accessor *CONFIG
|
24
|
+
|
25
|
+
# Public: Initializes a new Ecwid Authentication for OAuth
|
26
|
+
#
|
27
|
+
# Examples
|
28
|
+
#
|
29
|
+
# app = EcwidApi::Authentication.new do |config|
|
30
|
+
# config.client_id = "some client id"
|
31
|
+
# config.client_secret = "some client secret"
|
32
|
+
# config.scope "this_is_what_i_want_to_do oh_and_that_too"
|
33
|
+
# config.redirect_uri = "https://example.com/oauth"
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
def initialize
|
37
|
+
yield(self) if block_given?
|
38
|
+
CONFIG.each do |method|
|
39
|
+
raise Error.new("#{method} is required to initialize a new EcwidApi::Authentication") unless send(method)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Public: The URL for OAuth authorization.
|
44
|
+
#
|
45
|
+
# This is the URL that the user will need to go to to authorize the app
|
46
|
+
# with the Ecwid store.
|
47
|
+
#
|
48
|
+
def oauth_url
|
49
|
+
"https://my.ecwid.com/api/oauth/authorize?" + oauth_query
|
50
|
+
end
|
51
|
+
|
52
|
+
# Public: Obtain the access token in order to use the API
|
53
|
+
#
|
54
|
+
# code - the temporary code obtained from the authorization callback
|
55
|
+
#
|
56
|
+
# Examples
|
57
|
+
#
|
58
|
+
# token = app.access_token(params[:code])
|
59
|
+
# token.access_token # the access token that authenticates each API request
|
60
|
+
# token.store_id # the authenticated Ecwid store_id
|
61
|
+
#
|
62
|
+
# Returns an OpenStruct which responds with the information needed to
|
63
|
+
# access the API for a store.
|
64
|
+
def access_token(code)
|
65
|
+
response = connection.post("/api/oauth/token",
|
66
|
+
client_id: client_id,
|
67
|
+
client_secret: client_secret,
|
68
|
+
code: code,
|
69
|
+
redirect_uri: redirect_uri,
|
70
|
+
grant_type: "authorization_code"
|
71
|
+
)
|
72
|
+
|
73
|
+
if response.success?
|
74
|
+
OpenStruct.new(response.body)
|
75
|
+
else
|
76
|
+
raise Error.new(response.body["error_description"])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# Private: The query parameters for the OAuth authorization request
|
83
|
+
#
|
84
|
+
# Returns a String of query parameters
|
85
|
+
def oauth_query
|
86
|
+
{
|
87
|
+
client_id: client_id,
|
88
|
+
scope: scope,
|
89
|
+
response_type: "code",
|
90
|
+
redirect_uri: redirect_uri
|
91
|
+
}.map do |key, val|
|
92
|
+
"#{CGI.escape(key.to_s)}=#{CGI.escape(val.to_s)}"
|
93
|
+
end.join(?&)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Private: Returns a connection for obtaining an access token from Ecwid
|
97
|
+
#
|
98
|
+
def connection
|
99
|
+
@connection ||= Faraday.new "https://my.ecwid.com" do |conn|
|
100
|
+
conn.request :url_encoded
|
101
|
+
conn.response :json, content_type: /\bjson$/
|
102
|
+
conn.adapter Faraday.default_adapter
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module EcwidApi
|
2
|
+
# Public: This is an Ecwid Order
|
3
|
+
class Order < Entity
|
4
|
+
self.url_root = "orders"
|
5
|
+
|
6
|
+
ecwid_reader :orderNumber, :vendorOrderNumber, :subtotal, :total, :email,
|
7
|
+
:paymentMethod, :paymentModule, :tax, :ipAddress,
|
8
|
+
:couponDiscount, :paymentStatus, :fulfillmentStatus,
|
9
|
+
:refererUrl, :orderComments, :volumeDiscount, :customerId,
|
10
|
+
:membershipBasedDiscount, :totalAndMembershipBasedDiscount,
|
11
|
+
:discount, :usdTotal, :globalReferer, :createDate, :updateDate,
|
12
|
+
:customerGroup, :discountCoupon, :items, :billingPerson,
|
13
|
+
:shippingPerson, :shippingOption, :additionalInfo,
|
14
|
+
:paymentParams, :discountInfo, :trackingNumber,
|
15
|
+
:paymentMessage, :extTransactionId, :affiliateId,
|
16
|
+
:creditCardStatus
|
17
|
+
|
18
|
+
|
19
|
+
ecwid_writer :subtotal, :total, :email, :paymentMethod, :paymentModule,
|
20
|
+
:tax, :ipAddress, :couponDiscount, :paymentStatus,
|
21
|
+
:fulfillmentStatus, :refererUrl, :orderComments,
|
22
|
+
:volumeDiscount, :customerId, :membershipBasedDiscount,
|
23
|
+
:totalAndMembershipBasedDiscount, :discount, :globalReferer,
|
24
|
+
:createDate, :updateDate, :customerGroup, :discountCoupon,
|
25
|
+
:items, :billingPerson, :shippingPerson, :shippingOption,
|
26
|
+
:additionalInfo, :paymentParams, :discountInfo,
|
27
|
+
:trackingNumber, :paymentMessage, :extTransactionId,
|
28
|
+
:affiliateId, :creditCardStatus
|
29
|
+
|
30
|
+
VALID_FULFILLMENT_STATUSES = %w(
|
31
|
+
AWAITING_PROCESSING
|
32
|
+
PROCESSING
|
33
|
+
SHIPPED
|
34
|
+
DELIVERED
|
35
|
+
WILL_NOT_DELIVER
|
36
|
+
RETURNED
|
37
|
+
)
|
38
|
+
|
39
|
+
# Public: Gets the unique ID of the order
|
40
|
+
def id
|
41
|
+
order_number
|
42
|
+
end
|
43
|
+
|
44
|
+
# Public: Returns the billing person
|
45
|
+
def billing_person
|
46
|
+
return unless data["billingPerson"] || data["shippingPerson"]
|
47
|
+
|
48
|
+
@billing_person ||= if data["billingPerson"]
|
49
|
+
Person.new(data["billingPerson"])
|
50
|
+
else
|
51
|
+
shipping_person
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Public: Returns the shipping person
|
56
|
+
def shipping_person
|
57
|
+
return unless data["shippingPerson"] || data["billingPerson"]
|
58
|
+
@shipping_person ||= if data["shippingPerson"]
|
59
|
+
Person.new(data["shippingPerson"])
|
60
|
+
else
|
61
|
+
billing_person
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Public: Returns a Array of `OrderItem` objects
|
66
|
+
def items
|
67
|
+
@items ||= data["items"].map { |item| OrderItem.new(item) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def fulfillment_status=(status)
|
71
|
+
status = status.to_s.upcase
|
72
|
+
unless VALID_FULFILLMENT_STATUSES.include?(status)
|
73
|
+
raise Error("#{status} is an invalid fullfillment status")
|
74
|
+
end
|
75
|
+
super(status)
|
76
|
+
end
|
77
|
+
|
78
|
+
def fulfillment_status
|
79
|
+
super && super.downcase.to_sym
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module EcwidApi
|
2
|
+
class OrderItem < Entity
|
3
|
+
ecwid_reader :id, :productId, :categoryId, :price, :productPrice, :weight,
|
4
|
+
:sku, :quantity, :shortDescription, :tax, :shipping,
|
5
|
+
:quantityInStock, :name, :tangible, :trackQuantity,
|
6
|
+
:fixedShippingRateOnly, :imageId, :fixedShippingRate,
|
7
|
+
:digital, :productAvailable, :couponApplied, :selectedOptions,
|
8
|
+
:taxes, :files
|
9
|
+
|
10
|
+
# Public: Returns the default `Category` that the product belongs to
|
11
|
+
def category
|
12
|
+
client.categories.find(data["categoryId"])
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO: get the product
|
16
|
+
end
|
17
|
+
end
|