ecwid_api 0.0.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +8 -0
  3. data/README.md +123 -31
  4. data/ecwid_api.gemspec +10 -8
  5. data/lib/ecwid_api.rb +18 -29
  6. data/lib/ecwid_api/api.rb +12 -0
  7. data/lib/ecwid_api/api/base.rb +18 -0
  8. data/lib/ecwid_api/api/categories.rb +56 -0
  9. data/lib/ecwid_api/api/customers.rb +53 -0
  10. data/lib/ecwid_api/api/orders.rb +36 -0
  11. data/lib/ecwid_api/api/product_combinations.rb +48 -0
  12. data/lib/ecwid_api/api/product_types.rb +56 -0
  13. data/lib/ecwid_api/api/products.rb +148 -0
  14. data/lib/ecwid_api/category.rb +53 -4
  15. data/lib/ecwid_api/client.rb +65 -58
  16. data/lib/ecwid_api/customer.rb +10 -0
  17. data/lib/ecwid_api/entity.rb +151 -29
  18. data/lib/ecwid_api/error.rb +10 -0
  19. data/lib/ecwid_api/o_auth.rb +106 -0
  20. data/lib/ecwid_api/order.rb +118 -0
  21. data/lib/ecwid_api/order_item.rb +17 -0
  22. data/lib/ecwid_api/paged_ecwid_response.rb +57 -0
  23. data/lib/ecwid_api/paged_enumerator.rb +66 -0
  24. data/lib/ecwid_api/person.rb +7 -0
  25. data/lib/ecwid_api/product.rb +65 -0
  26. data/lib/ecwid_api/product_combination.rb +30 -0
  27. data/lib/ecwid_api/product_type.rb +18 -0
  28. data/lib/ecwid_api/product_type_attribute.rb +27 -0
  29. data/lib/ecwid_api/unpaged_ecwid_response.rb +38 -0
  30. data/lib/ecwid_api/version.rb +1 -1
  31. data/lib/ext/string.rb +9 -1
  32. data/spec/api/categories_spec.rb +31 -0
  33. data/spec/api/customers_spec.rb +20 -0
  34. data/spec/api/orders_spec.rb +30 -0
  35. data/spec/api/product_types_spec.rb +20 -0
  36. data/spec/api/products_spec.rb +20 -0
  37. data/spec/category_spec.rb +1 -6
  38. data/spec/client_spec.rb +4 -32
  39. data/spec/entity_spec.rb +120 -8
  40. data/spec/fixtures/categories.json +28 -22
  41. data/spec/fixtures/classes.json +44 -0
  42. data/spec/fixtures/customers.json +48 -0
  43. data/spec/fixtures/order.json +162 -0
  44. data/spec/fixtures/orders.json +303 -0
  45. data/spec/fixtures/products.json +141 -0
  46. data/spec/helpers/client.rb +34 -0
  47. data/spec/oauth_spec.rb +40 -0
  48. data/spec/order_item_spec.rb +12 -0
  49. data/spec/order_spec.rb +71 -0
  50. data/spec/paged_enumerator_spec.rb +38 -0
  51. data/spec/spec_helper.rb +3 -3
  52. metadata +93 -37
  53. data/lib/ecwid_api/category_api.rb +0 -62
  54. data/spec/category_api_spec.rb +0 -36
  55. data/spec/ecwid_api_spec.rb +0 -15
  56. data/spec/helpers/faraday.rb +0 -30
@@ -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
@@ -0,0 +1,57 @@
1
+ require_relative 'paged_enumerator'
2
+
3
+ # Public: Presents a paged Ecwid response as an Enumerator with a
4
+ # PagedEnumerator
5
+ #
6
+ # Example
7
+ #
8
+ # response = PagedEcwidResponse.new(client, "products", priceFrom: 10) do |product_hash|
9
+ # Product.new(product_hash, click: client)
10
+ # end
11
+ #
12
+ # response.each do |product|
13
+ # # do stuff the the product
14
+ # end
15
+ #
16
+ module EcwidApi
17
+ class PagedEcwidResponse
18
+ include Enumerable
19
+ extend Forwardable
20
+
21
+ def_delegator :@paged_enumerator, :each
22
+
23
+ # Public: Initialize a new PagedEcwidResponse
24
+ #
25
+ # client - an EcwidApi::Client
26
+ # path - a String that is the path to retrieve from the client
27
+ # params - a Hash of parameters to pass along with the request
28
+ # &block - a Block that processes each item returned in the Response
29
+ #
30
+ def initialize(client, path, params = {}, &block)
31
+ params[:limit] = 100
32
+ params.delete(:offset)
33
+
34
+ block ||= proc { |item| item }
35
+
36
+ response = client.get(path, params)
37
+
38
+ @paged_enumerator = PagedEnumerator.new(response) do |enum_response, yielder|
39
+ count, offset, total = %w[count offset total].map do |i|
40
+ enum_response.body[i].to_i
41
+ end
42
+
43
+ if count > 0
44
+ enum_response.body['items'].each do |item|
45
+ yielder << block.call(item)
46
+ end
47
+ end
48
+
49
+ if count.zero? || count + offset >= total
50
+ false
51
+ else
52
+ client.get(path, params.merge(offset: offset + count))
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,66 @@
1
+ module EcwidApi
2
+ # Public: Abstracts pagination into an Enumerator so all of the objects for
3
+ # a given response can be retreived without having to know that they were
4
+ # split into pages from the server
5
+ #
6
+ # Examples
7
+ #
8
+ # client.get("orders", limit: 10)
9
+ #
10
+ # paged = PagedEnumerator.new(orders) do |response, yielder|
11
+ # response.body["orders"].each do |obj|
12
+ # yielder << obj
13
+ # end
14
+ #
15
+ # next_url = response.body["nextUrl"]
16
+ # next_url ? client.get(next_url) : false
17
+ # end
18
+ #
19
+ # paged.each do |item|
20
+ # puts item.inspect
21
+ # end
22
+ #
23
+ class PagedEnumerator
24
+ include Enumerable
25
+
26
+ # Private: A response that we are evaluating
27
+ attr_reader :response
28
+ private :response
29
+
30
+ # Private: Gets the next response
31
+ attr_reader :next_block
32
+ private :next_block
33
+
34
+ # Public: Initializes a new PagedEnumerator
35
+ #
36
+ # response - the response that contains a collection of objects
37
+ # next_block - The block will receive the response and a yielder Proc.
38
+ # The block should use `yielder << item` to yield all of
39
+ # the items in the collection.
40
+ #
41
+ # Then the block should return the next response. If no
42
+ # response is given (eg: the last page), the block should
43
+ # return a falsey value.
44
+ #
45
+ def initialize(response, &next_block)
46
+ @response, @next_block = response, next_block
47
+ end
48
+
49
+ # Public: Iterates over each "page" yielding each "item" in every collection
50
+ def each(&block)
51
+ unless @next_enumerator
52
+ @yielder ||= []
53
+ @next_response ||= next_block.call(response, @yielder)
54
+
55
+ if @next_response
56
+ @next_enumerator ||= PagedEnumerator.new(@next_response, &@next_block)
57
+ else
58
+ @next_enumerator = []
59
+ end
60
+ end
61
+
62
+ @yielder.each(&block)
63
+ @next_enumerator.each(&block)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,7 @@
1
+ module EcwidApi
2
+ class Person < Entity
3
+ ecwid_reader :name, :companyName, :street, :city, :countryCode,
4
+ :countryName, :postalCode, :stateOrProvinceCode,
5
+ :stateOrProvinceName, :phone
6
+ end
7
+ end
@@ -0,0 +1,65 @@
1
+ module EcwidApi
2
+ class Product < Entity
3
+ self.url_root = "products"
4
+
5
+ ecwid_reader :id, :sku, :quantity, :unlimited, :inStock, :name, :price,
6
+ :priceInProductList, :wholesalePrices, :compareToPrice,
7
+ :weight, :url, :created, :updated, :productClassId,
8
+ :enabled, :options, :warningLimit, :fixedShippingRateOnly,
9
+ :fixedShippingRate, :defaultCombinationId, :thumbnailUrl,
10
+ :imageUrl, :smallThumbnailUrl, :originalImageUrl, :description,
11
+ :galleryImages, :categoryIds, :defaultCategoryId, :favorites,
12
+ :attributes, :files, :relatedProducts, :combinations
13
+
14
+ ecwid_writer :sku, :name, :quantity, :price, :wholesalePrices,
15
+ :compareToPrice, :weight, :productClassId, :enabled, :options,
16
+ :warningLimit, :fixedShippingRateOnly, :fixedShippingRate,
17
+ :description, :categoryIds, :defaultCategoryId, :attributes,
18
+ :relatedProducts
19
+
20
+ # Public: Uploads a primary image for a Product
21
+ #
22
+ # filename - a String that is either a local file name or URL
23
+ #
24
+ # Raises ResponseError if the API returns an error
25
+ #
26
+ # Returns a Faraday::Response object
27
+ def upload_image!(filename)
28
+ client.post_image("#{url}/image", filename)
29
+ end
30
+
31
+ # Public: Uploads gallery images for a Product
32
+ #
33
+ # *filenames - Strings that are either a local file name or URL
34
+ #
35
+ # Raises ResponseError if the API returns an error
36
+ #
37
+ # Returns an Array of Faraday::Response object
38
+ def upload_gallery_images!(*filenames)
39
+ filenames.map do |filename|
40
+ client.post_image("#{url}/gallery", filename)
41
+ end
42
+ end
43
+
44
+ # Public: Deletes all of the gallery images for a Product
45
+ #
46
+ # Raises ResponseError if the API returns an error
47
+ #
48
+ # Returns a Faraday::Response object
49
+ def delete_gallery_images!
50
+ client.delete("#{url}/gallery")
51
+ end
52
+
53
+ def combinations
54
+ @combinations ||= Api::ProductCombinations.new(self, client)
55
+ end
56
+
57
+ def created
58
+ @created ||= Time.parse(super)
59
+ end
60
+
61
+ def updated
62
+ @updated ||= Time.parse(super)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,30 @@
1
+ module EcwidApi
2
+ class ProductCombination < Entity
3
+ attr_reader :product
4
+
5
+ self.url_root = -> { "products/#{product.id}/combinations" }
6
+
7
+ ecwid_reader :id, :combinationNumber, :options, :sku, :smallThumbnailUrl,
8
+ :thumbnailUrl, :imageUrl, :originalImageUrl, :quantity,
9
+ :unlimited, :price, :wholesalePrices, :weight, :warningLimit
10
+
11
+ ecwid_writer :options, :sku, :quantity, :unlimited, :price,
12
+ :wholesalePrices, :weight, :warningLimit, :inventoryDelta
13
+
14
+ def initialize(data, opts={})
15
+ super(data, opts)
16
+ @product = opts[:product]
17
+ end
18
+
19
+ # Public: Uploads a primary image for a ProductCombination
20
+ #
21
+ # filename - a String that is either a local file name or URL
22
+ #
23
+ # Raises ResponseError if the API returns an error
24
+ #
25
+ # Returns a Faraday::Response object
26
+ def upload_image!(filename)
27
+ client.post_image("#{url}/image", filename)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ module EcwidApi
2
+ class ProductType < Entity
3
+
4
+ self.url_root = "classes"
5
+
6
+ ecwid_reader :id, :name, :googleTaxonomy, :attributes
7
+
8
+ ecwid_writer :name, :attributes
9
+
10
+
11
+ # Public: Returns a Array of `ProductTypeAttribute` objects
12
+ def attributes
13
+ @attributes ||= data["attributes"].map { |attribute| ProductTypeAttribute.new(attribute) }
14
+ end
15
+
16
+
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ module EcwidApi
2
+ class ProductTypeAttribute < Entity
3
+
4
+ ecwid_reader :id, :name, :type, :show
5
+
6
+ VALID_TYPES = %w(CUSTOM UPC BRAND GENDER AGE_GROUP COLOR SIZE PRICE_PER_UNIT UNITS_IN_PRODUCT)
7
+ VALID_SHOWS = %w(NOTSHOW DESCR PRICE)
8
+
9
+
10
+ def type=(type_type)
11
+ type_type = type_type.to_s.upcase
12
+ unless VALID_TYPES.include?(type_type)
13
+ raise ::StandardError.new("#{type_type} is an invalid 'type'")
14
+ end
15
+ super(type_type)
16
+ end
17
+
18
+
19
+ def show=(show_type)
20
+ show_type = show_type.to_s.upcase
21
+ unless VALID_SHOWS.include?(show_type)
22
+ raise ::StandardError.new("#{show_type} is an invalid 'show'")
23
+ end
24
+ super(show_type)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,38 @@
1
+
2
+ # Public: Presents an Ecwid response as an Array
3
+ #
4
+ # Example
5
+ #
6
+ # response = UnpagedEcwidResponse.new(client, "products", priceFrom: 10) do |product_hash|
7
+ # Product.new(product_hash, click: client)
8
+ # end
9
+ #
10
+ # response.each do |product|
11
+ # # do stuff the the product
12
+ # end
13
+ #
14
+ module EcwidApi
15
+ class UnpagedEcwidResponse
16
+ include Enumerable
17
+ extend Forwardable
18
+
19
+ def_delegators :@records, *Enumerable.instance_methods
20
+
21
+ # Public: Initialize a new UnpagedEcwidResponse
22
+ #
23
+ # client - an EcwidApi::Client
24
+ # path - a String that is the path to retrieve from the client
25
+ # params - a Hash of parameters to pass along with the request
26
+ # &block - a Block that processes each item returned in the Response
27
+ #
28
+ def initialize(client, path, params = {}, &block)
29
+ block ||= Proc.new { |item| item }
30
+ @records = []
31
+
32
+ response = client.get(path, params)
33
+ response.body.each do |item|
34
+ @records << block.call(item)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module EcwidApi
2
- VERSION = "0.0.2"
2
+ VERSION = "0.2.3"
3
3
  end
@@ -1,5 +1,13 @@
1
1
  class String
2
2
  def camel_case
3
3
  split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
4
- end
4
+ end unless method_defined?(:camel_case)
5
+
6
+ def underscore
7
+ self.gsub(/::/, '/').
8
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
9
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
10
+ tr("-", "_").
11
+ downcase
12
+ end unless method_defined?(:underscore)
5
13
  end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe EcwidApi::Api::Categories, faraday: true do
4
+ subject { client.categories }
5
+
6
+ describe "#all" do
7
+ it "gets all of the categories from the client" do
8
+ expect(client).to receive(:get).with("categories", hash_including({})).and_call_original
9
+ subject.all
10
+ end
11
+
12
+ it "gets sub categories" do
13
+ expect(client).to receive(:get).with("categories", hash_including(parent: 5)).and_call_original
14
+ subject.all(parent: 5)
15
+ end
16
+ end
17
+
18
+ describe "#root" do
19
+ it "gets the root level categories" do
20
+ expect(subject).to receive(:all).with(hash_including(parent: 0)).and_call_original
21
+ subject.root
22
+ end
23
+ end
24
+
25
+ describe "#find" do
26
+ it "finds a single category" do
27
+ expect(client).to receive(:get).with("categories/#{5}").and_call_original
28
+ subject.find(5)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe EcwidApi::Api::Customers, faraday: true do
4
+ subject { client.customers }
5
+
6
+ describe "#all" do
7
+ it "passes any other parameters through" do
8
+ expect(client).to receive(:get).with("customers", hash_including(from_date: '1982-05-17'))
9
+ subject.all(from_date: '1982-05-17')
10
+ end
11
+
12
+ it "gets the proper response count (see fixture)" do
13
+ expect(subject.all.count).to eq 5
14
+ end
15
+
16
+ it "gets the proper customer (see fixture)" do
17
+ expect(subject.all.first.name).to eq "Abe Doe"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe EcwidApi::Api::Orders, faraday: true do
4
+ subject { client.orders }
5
+
6
+ describe "#all" do
7
+ it "passes the parameters to the client" do
8
+ expect(client).to receive(:get).with("orders", hash_including(from_date: '1982-05-17'))
9
+ subject.all(from_date: '1982-05-17')
10
+ end
11
+
12
+ it "gets the proper response (see fixtures)" do
13
+ expect(subject.all.count).to be 2
14
+ end
15
+
16
+ it "gets EcwidApi::Order types" do
17
+ expect(subject.all.all? { |order| order.is_a?(EcwidApi::Order) }).to be(true)
18
+ end
19
+ end
20
+
21
+ describe "#find" do
22
+ it "is an `EcwidApi::Order`" do
23
+ expect(subject.find(35)).to be_a(EcwidApi::Order)
24
+ end
25
+
26
+ it "is nil when not found" do
27
+ expect(subject.find(404)).to be_nil
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe EcwidApi::Api::ProductTypes, faraday: true do
4
+ subject { client.product_types }
5
+
6
+ describe "#all" do
7
+ it "returns an array" do
8
+ expect(client).to receive(:get).with("classes", {}).and_call_original
9
+ subject.all
10
+ end
11
+
12
+ it "gets the proper response count (see fixture)" do
13
+ expect(subject.all.count).to eq 2
14
+ end
15
+
16
+ it "gets the proper product_type (see fixture)" do
17
+ expect(subject.all.first.name).to eq "Foo"
18
+ end
19
+ end
20
+ end