ecwid_api 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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