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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +8 -0
  3. data/Gemfile +2 -0
  4. data/README.md +228 -144
  5. data/ecwid_api.gemspec +1 -0
  6. data/lib/ecwid_api/api/base.rb +17 -0
  7. data/lib/ecwid_api/api/categories.rb +57 -0
  8. data/lib/ecwid_api/api/orders.rb +36 -0
  9. data/lib/ecwid_api/api/product_combinations.rb +51 -0
  10. data/lib/ecwid_api/api/products.rb +64 -0
  11. data/lib/ecwid_api/api.rb +31 -0
  12. data/lib/ecwid_api/category.rb +59 -4
  13. data/lib/ecwid_api/client.rb +65 -94
  14. data/lib/ecwid_api/entity.rb +138 -26
  15. data/lib/ecwid_api/error.rb +12 -2
  16. data/lib/ecwid_api/o_auth.rb +106 -0
  17. data/lib/ecwid_api/order.rb +82 -0
  18. data/lib/ecwid_api/order_item.rb +17 -0
  19. data/lib/ecwid_api/paged_ecwid_response.rb +55 -0
  20. data/lib/ecwid_api/paged_enumerator.rb +66 -0
  21. data/lib/ecwid_api/person.rb +7 -0
  22. data/lib/ecwid_api/product.rb +77 -0
  23. data/lib/ecwid_api/product_combination.rb +34 -0
  24. data/lib/ecwid_api/version.rb +1 -1
  25. data/lib/ecwid_api.rb +25 -39
  26. data/lib/ext/string.rb +12 -4
  27. data/spec/api/categories_spec.rb +31 -0
  28. data/spec/api/orders_spec.rb +30 -0
  29. data/spec/api/products_spec.rb +20 -0
  30. data/spec/category_spec.rb +33 -38
  31. data/spec/client_spec.rb +20 -48
  32. data/spec/entity_spec.rb +90 -5
  33. data/spec/fixtures/categories.json +28 -22
  34. data/spec/fixtures/order.json +162 -0
  35. data/spec/fixtures/orders.json +302 -0
  36. data/spec/fixtures/products.json +141 -0
  37. data/spec/helpers/client.rb +32 -0
  38. data/spec/oauth_spec.rb +40 -0
  39. data/spec/order_item_spec.rb +12 -0
  40. data/spec/order_spec.rb +71 -0
  41. data/spec/paged_enumerator_spec.rb +38 -0
  42. data/spec/spec_helper.rb +24 -23
  43. metadata +53 -9
  44. data/lib/ecwid_api/category_api.rb +0 -62
  45. data/spec/category_api_spec.rb +0 -36
  46. data/spec/ecwid_api_spec.rb +0 -15
  47. 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
@@ -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
- parent_id = data["parentId"]
11
- client.categories.find(parent_id) if parent_id
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
@@ -1,95 +1,66 @@
1
- require 'faraday'
2
- require 'faraday_middleware'
3
-
4
- module EcwidApi
5
- # Public: Client objects manage the connection and interface to a single Ecwid
6
- # store.
7
- #
8
- # Examples
9
- #
10
- # client = EcwidApi::Client.new do |config|
11
- # config.store_id = '12345'
12
- # config.url = 'http://app.ecwid.com/api/v1'
13
- # config.order_secret_key = 'ORDER_SECRET_KEY'
14
- # config.product_secret_key = 'PRODUCT_SECRET_KEY'
15
- # end
16
- #
17
- class Client
18
- # The default base URL for the Ecwid API
19
- DEFAULT_URL = "https://app.ecwid.com/api/v1"
20
-
21
- # Public: Returns the Ecwid Store ID
22
- attr_reader :store_id
23
-
24
- # Public: Gets or sets the Order API Secret Key for the Ecwid Store
25
- attr_accessor :order_secret_key
26
-
27
- # Public: Gets or sets the default Product API Secret Key for the Ecwid Store
28
- attr_accessor :product_secret_key
29
-
30
- def initialize
31
- yield(self) if block_given?
32
- raise Error.new("The store_id is required") unless store_id
33
- end
34
-
35
- # Public: Returns the base URL of the Ecwid API
36
- def url
37
- @url || DEFAULT_URL
38
- end
39
-
40
- # Public: Sets the base URL for the Ecwid API
41
- def url=(url)
42
- reset_connection
43
- @url = url
44
- end
45
-
46
- # Public: Sets the Ecwid Store ID
47
- def store_id=(store_id)
48
- reset_connection
49
- @store_id = store_id
50
- end
51
-
52
- # Public: The URL of the API for the Ecwid Store
53
- def store_url
54
- "#{url}/#{store_id}"
55
- end
56
-
57
- # Public: Sends a GET request to the Ecwid API
58
- #
59
- # path - The String path for the URL of the request without the base URL
60
- # params - A Hash of query string parameters
61
- #
62
- # Examples
63
- #
64
- # # Gets the Categories where the parent Category is 1
65
- # client.get("categories", parent: 1)
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
@@ -1,12 +1,86 @@
1
1
  module EcwidApi
2
2
  class Entity
3
- # Private: Gets the Client
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
- private :data
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: Get a property of the data (snake_case)
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
- # Examples
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
- # entity.parent_id # same as `entity["parentId"]`
150
+ # Saves anything stored in the @new_data hash
48
151
  #
49
- # TODO: #method_missing isn't the ideal solution because Ecwid will only
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
- # Returns the value of the property
57
- def method_missing(method, *args)
58
- method_string = method.to_s
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
- [ method_string, method_string.camel_case ].each do |key|
61
- return data[key] if data.has_key?(key)
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
- super method, *args
175
+ def to_json(*args)
176
+ data.to_json(*args)
65
177
  end
66
178
  end
67
179
  end
@@ -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