ecwid_api 0.0.2 → 0.2.3
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 +5 -5
- data/.travis.yml +8 -0
- data/README.md +123 -31
- data/ecwid_api.gemspec +10 -8
- data/lib/ecwid_api.rb +18 -29
- data/lib/ecwid_api/api.rb +12 -0
- data/lib/ecwid_api/api/base.rb +18 -0
- data/lib/ecwid_api/api/categories.rb +56 -0
- data/lib/ecwid_api/api/customers.rb +53 -0
- data/lib/ecwid_api/api/orders.rb +36 -0
- data/lib/ecwid_api/api/product_combinations.rb +48 -0
- data/lib/ecwid_api/api/product_types.rb +56 -0
- data/lib/ecwid_api/api/products.rb +148 -0
- data/lib/ecwid_api/category.rb +53 -4
- data/lib/ecwid_api/client.rb +65 -58
- data/lib/ecwid_api/customer.rb +10 -0
- data/lib/ecwid_api/entity.rb +151 -29
- data/lib/ecwid_api/error.rb +10 -0
- data/lib/ecwid_api/o_auth.rb +106 -0
- data/lib/ecwid_api/order.rb +118 -0
- data/lib/ecwid_api/order_item.rb +17 -0
- data/lib/ecwid_api/paged_ecwid_response.rb +57 -0
- data/lib/ecwid_api/paged_enumerator.rb +66 -0
- data/lib/ecwid_api/person.rb +7 -0
- data/lib/ecwid_api/product.rb +65 -0
- data/lib/ecwid_api/product_combination.rb +30 -0
- data/lib/ecwid_api/product_type.rb +18 -0
- data/lib/ecwid_api/product_type_attribute.rb +27 -0
- data/lib/ecwid_api/unpaged_ecwid_response.rb +38 -0
- data/lib/ecwid_api/version.rb +1 -1
- data/lib/ext/string.rb +9 -1
- data/spec/api/categories_spec.rb +31 -0
- data/spec/api/customers_spec.rb +20 -0
- data/spec/api/orders_spec.rb +30 -0
- data/spec/api/product_types_spec.rb +20 -0
- data/spec/api/products_spec.rb +20 -0
- data/spec/category_spec.rb +1 -6
- data/spec/client_spec.rb +4 -32
- data/spec/entity_spec.rb +120 -8
- data/spec/fixtures/categories.json +28 -22
- data/spec/fixtures/classes.json +44 -0
- data/spec/fixtures/customers.json +48 -0
- data/spec/fixtures/order.json +162 -0
- data/spec/fixtures/orders.json +303 -0
- data/spec/fixtures/products.json +141 -0
- data/spec/helpers/client.rb +34 -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 +3 -3
- metadata +93 -37
- 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,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,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
|
data/lib/ecwid_api/version.rb
CHANGED
data/lib/ext/string.rb
CHANGED
@@ -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
|