cornerstore 0.6.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dfc2a280092553731812a736e6e328ca98c4684a
4
+ data.tar.gz: 91b3b7e4604d61bf9de7f93f5e9eddfda886bffb
5
+ SHA512:
6
+ metadata.gz: 0dfd5351f44be439ac06b31fb00d62434affced7c7549f5007cfb14f8aa517f0afe02387e914ebbe0867d1c898913f788fbf77c6bb95d53c7596be294a94c402
7
+ data.tar.gz: d3eae73f7a1b60d331b2ec5172b09a9094b029f98cccaa13cb743d3c4fd91228c9ec22cb300855f93874ce4956cc8d6fe306fed7c22fd5e2ea6d9139d88161b5
@@ -0,0 +1,15 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cornerstore.gemspec
4
+ gemspec
@@ -0,0 +1,75 @@
1
+ # Cornerstore
2
+
3
+ This is a client for the Cornerstore API-based online shop. Cornerstore allows you to create custom online shops
4
+ with your own front-end code, platform and tool belt choices. Instead of reinventing the wheel however, Cornerstore will
5
+ supply you with common e-commerce resources like products and carts via API. It also includes a checkout and Manager interface,
6
+ so your customers can manage their products and orders without you having to code yet another admin back-end.
7
+
8
+ Learn more about Cornerstore at http://www.cornerstore.io and http://addons.heroku.com/cornerstore
9
+
10
+ ## Authentication
11
+
12
+ The gem tries to retrieve your Cornerstore credentials in the following order:
13
+
14
+ 1. It checks if the env variable CORNERSTORE_URL is set and extracts the credentials. If you provisioned
15
+ with Heroku this variable is already configured.
16
+
17
+ 2. If no env variable is available it checks the secrets.yml file on Rails 4.1 or looks for a
18
+ cornerstore.yml on previous versions. See examples/cornerstore.yml for an example.
19
+
20
+ 3. You can always set the credentials directly by using the Cornerstore.subdomain= and Cornerstore.api_key=
21
+ methods.
22
+
23
+ ## Getting products & collections
24
+
25
+ You can retrieve products from Cornerstore like so:
26
+
27
+ product = Cornerstore::Product.find('sugo-al-basilico')
28
+ product.manufacturer #=> "Fattoria Croccante"
29
+
30
+ product = Cornerstore::Product.find('5900338280000393023')
31
+ product.name #=> "Sugo Al Basilico"
32
+
33
+ collection = Cornerstore::Collection.find('spaghetti').child_collections.first
34
+ product = collection.products.first
35
+ product.variants.any? #=> true
36
+ product.variants.first.price.decimal_amount #=> 12.99
37
+
38
+ ## Creating carts and adding line items
39
+
40
+ You can create carts and handle line items as state below. Line items can either be created from scratch or you can
41
+ derive them from a product/variant.
42
+
43
+ cart = Cornerstore::Cart.new({
44
+ success_redirect_url: "http://yourshop.com/cart/success",
45
+ cart_url: "http://yourshop.com/cart"
46
+ })
47
+
48
+ product = Cornerstore::Product.find('sugo-al-basilico')
49
+ variant = product.variants.find('SBS-39993')
50
+
51
+ # Derive from variant
52
+ cart.line_items.create_from_variant(variant, qty: 10)
53
+
54
+ line_item = cart.line_items.first
55
+ line_item.qty = 15
56
+ line_item.save
57
+
58
+ another_line_item = cart.line_items.last
59
+ another_line_item.destroy
60
+
61
+ # Create a line item directly
62
+ line_item = Cornerstore::LineItem.create({
63
+ qty: 10,
64
+ description: 'My own custom line item',
65
+ unit: 'Piece',
66
+ weight: 0.5,
67
+ price: Cornerstore::Price.new(12.99, 'USD')
68
+ })
69
+
70
+ ## Learn more
71
+
72
+ We provide a full API documentation at http://developer.cornerstore.io/api, including many ruby examples. Generally every
73
+ attribute that is listed in the API docs corresponds to a ruby method that can be called on the respective objects. In
74
+ many cases there are additional methods available, just check out the classes of this gem and our Rails example store
75
+ and boilerplate at https://github.com/crispymtn/fattoria-croccante.
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cornerstore/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "cornerstore"
8
+ gem.version = Cornerstore::VERSION
9
+ gem.authors = ['Johannes Treitz', 'Christian Weyer']
10
+ gem.email = ['jt@crispymtn.com', 'cw@crispymtn.com']
11
+ gem.description = "This is a client for the Cornerstore e-commerce API"
12
+ gem.summary = "This is a client for the Cornerstore e-commerce API"
13
+ gem.homepage = "https://www.github.com/crispymtn/cornerstore-gem"
14
+ gem.files = `git ls-files`.split($/)
15
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.add_dependency 'rest-client'
20
+ gem.add_dependency 'activemodel'
21
+ gem.add_development_dependency "rspec"
22
+
23
+ end
@@ -0,0 +1,11 @@
1
+ development:
2
+ subdomain: your-shop-staging
3
+ api_key: dffe7d7382199992dfe # You find the API keys in the Cornerstore Manager under Settings > API
4
+
5
+ test:
6
+ subdomain: your-shop-staging
7
+ api_key: dffe7d7382199992dfe
8
+
9
+ production:
10
+ subdomain: your-shop
11
+ api_key: deee636888117727782
@@ -0,0 +1,84 @@
1
+ require 'active_model'
2
+ require 'rest_client'
3
+
4
+ require 'cornerstore/version'
5
+ require 'cornerstore/resource'
6
+ require 'cornerstore/model'
7
+ require 'cornerstore/api'
8
+
9
+ module RestClient::AbstractResponse
10
+ def success?
11
+ (200..207).include? code
12
+ end
13
+ end
14
+
15
+ RestClient.log = 'stdout'
16
+
17
+ module Cornerstore
18
+ class << self
19
+ attr_writer :subdomain, :api_key
20
+ end
21
+
22
+ def self.subdomain
23
+ @subdomain ||= read_config[:subdomain]
24
+ end
25
+
26
+ def self.root_url
27
+ "https://#{subdomain}.cornerstore.io/api/v1"
28
+ end
29
+
30
+ def self.assets_url
31
+ "http://cskit-production.s3.amazonaws.com"
32
+ end
33
+
34
+ def self.headers
35
+ {
36
+ user_agent: "cornerstore-gem/#{Cornerstore::VERSION}",
37
+ authorization: "Token #{api_key}"
38
+ }
39
+ end
40
+
41
+ private
42
+ # We have three levels of configuration
43
+ # - Can be manually set with accessors on this module
44
+ # - Can be supplied by Rails secret file
45
+ # - Can be supplied by a cornerstore yml file
46
+ # - Can be supplied via CORNERSTORE_URL env variable
47
+ def self.read_config
48
+ config = {}
49
+
50
+ # ENV variable set beats everything. If we got one we use it regardless
51
+ # of other config options
52
+ if ENV.has_key?('CORNERSTORE_URL') and uri = URI.parse(ENV['CORNERSTORE_URL'])
53
+ config[:subdomain] = uri.host.sub('.cornerstore.io', '')
54
+ config[:api_key] = uri.password
55
+
56
+ else
57
+ # Is this Rails?
58
+ if defined?(Rails)
59
+ # Try to get the credentials from the secret storage,
60
+ # if that fails try to read the YAML file
61
+ if not (Rails.application.respond_to?(:secrets) and
62
+ config[:subdomain] = Rails.application.secrets.cornerstore_subdomain and
63
+ config[:api_key] = Rails.application.secrets.cornerstore_api_key)
64
+
65
+ yml_path = Rails.root.join('config', 'cornerstore.yml')
66
+
67
+ if File.exists?(yml_path) and yaml = YAML.load(File.read(yml_path))
68
+ config[:subdomain] = yaml[Rails.env]['subdomain']
69
+ config[:api_key] = yaml[Rails.env]['api_key']
70
+ end
71
+ end
72
+
73
+ else
74
+ raise ArgumentError, 'Could not find any Cornerstore credentials, please set them before proceeding'
75
+ end
76
+ end
77
+
78
+ return config
79
+ end
80
+
81
+ def self.api_key
82
+ @api_ley ||= read_config[:api_key]
83
+ end
84
+ end
@@ -0,0 +1,18 @@
1
+ require 'cornerstore/api/product'
2
+ require 'cornerstore/api/variant'
3
+ require 'cornerstore/api/price'
4
+ require 'cornerstore/api/property'
5
+ require 'cornerstore/api/differentiating_property'
6
+ require 'cornerstore/api/image'
7
+ require 'cornerstore/api/collection'
8
+ require 'cornerstore/api/cart'
9
+ require 'cornerstore/api/line_item'
10
+ require 'cornerstore/api/search'
11
+
12
+ require 'cornerstore/api/order'
13
+ require 'cornerstore/api/payment_means'
14
+ require 'cornerstore/api/cancellation'
15
+ require 'cornerstore/api/shipment'
16
+ require 'cornerstore/api/carrier'
17
+ require 'cornerstore/api/address'
18
+ require 'cornerstore/api/customer'
@@ -0,0 +1,12 @@
1
+ class Cornerstore::Address < Cornerstore::Model::Base
2
+ attr_accessor :firstname,
3
+ :name,
4
+ :company,
5
+ :street,
6
+ :number,
7
+ :addition,
8
+ :town,
9
+ :zip,
10
+ :country,
11
+ :state
12
+ end
@@ -0,0 +1,22 @@
1
+ class Cornerstore::Cancellation < Cornerstore::Model::Base
2
+ attr_accessor :created_at,
3
+ :line_item_ids
4
+
5
+ alias_method :canceled_at, :created_at
6
+
7
+ def initialize(attributes = {}, parent=nil)
8
+ self.line_item_ids = attributes.delete('canceled_items')
9
+ self.created_at = DateTime.parse(attributes.delete('created_at')) unless attributes['created_at'].blank?
10
+
11
+ super
12
+ end
13
+
14
+ def line_items
15
+ return [] unless self.parent
16
+ self.parent.line_items.select { |li| self.line_item_ids.include?(li.id) }
17
+ end
18
+ alias_method :canceled_items, :line_items
19
+
20
+ class Resource < Cornerstore::Resource::Base
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ class Cornerstore::Carrier < Cornerstore::Model::Base
2
+ attr_accessor :name, :service
3
+ end
@@ -0,0 +1,49 @@
1
+ class Cornerstore::Cart < Cornerstore::Model::Base
2
+ include Cornerstore::Model::Writable
3
+
4
+ attr_accessor :line_items, :reference, :total, :success_redirect_url, :cart_url, :invoice_pdf_callback_url,
5
+ :delivery_note_pdf_callback_url, :placed_email_callback_url, :shipped_email_callback_url, :paid_email_callback_url, :canceled_email_callback_url
6
+
7
+ def initialize(attributes = {}, parent=nil)
8
+ self.total = Cornerstore::Price.new(attributes.delete('total'))
9
+ self.line_items = Cornerstore::LineItem::Resource.new(self, attributes.delete('line_items') || [], 'line_items')
10
+ super
11
+ end
12
+
13
+ def id
14
+ reference
15
+ end
16
+ alias to_param id
17
+
18
+ def attributes
19
+ {
20
+ reference: reference,
21
+ success_redirect_url: success_redirect_url,
22
+ cart_url: cart_url,
23
+ invoice_pdf_callback_url: invoice_pdf_callback_url,
24
+ delivery_note_pdf_callback_url: delivery_note_pdf_callback_url,
25
+ placed_email_callback_url: placed_email_callback_url,
26
+ shipped_email_callback_url: shipped_email_callback_url,
27
+ paid_email_callback_url: paid_email_callback_url,
28
+ canceled_email_callback_url: canceled_email_callback_url
29
+ }
30
+ end
31
+
32
+ def empty!
33
+ line_items.delete_all
34
+ line_items.empty?
35
+ end
36
+
37
+ def empty?
38
+ line_items.empty?
39
+ end
40
+
41
+ def checkout_url
42
+ "https://#{Cornerstore.subdomain}.cornerstore.io/checkout/#{self.reference}"
43
+ end
44
+
45
+ class Resource < Cornerstore::Resource::Base
46
+ include Cornerstore::Resource::Remote
47
+ include Cornerstore::Resource::Writable
48
+ end
49
+ end
@@ -0,0 +1,25 @@
1
+ class Cornerstore::Collection < Cornerstore::Model::Base
2
+ attr_accessor :name,
3
+ :parent,
4
+ :members,
5
+ :childs,
6
+ :products,
7
+ :properties
8
+
9
+ def initialize(attributes = {}, parent = nil)
10
+ self.products = Cornerstore::Product::Resource.new(self)
11
+ self.childs = Cornerstore::Collection::Resource.new(self, attributes.delete('child_collections') || [], 'childs')
12
+ self.properties = Cornerstore::Property::Resource.new(self, attributes.delete('properties') || [])
13
+ super
14
+ end
15
+
16
+ def attributes
17
+ {
18
+ name: name
19
+ }
20
+ end
21
+
22
+ class Resource < Cornerstore::Resource::Base
23
+ include Cornerstore::Resource::Remote
24
+ end
25
+ end
@@ -0,0 +1,4 @@
1
+ class Cornerstore::Customer < Cornerstore::Model::Base
2
+ attr_accessor :email,
3
+ :phone
4
+ end
@@ -0,0 +1,15 @@
1
+ class Cornerstore::DifferentiatingProperty < Cornerstore::Model::Base
2
+ attr_accessor :key,
3
+ :value
4
+
5
+ def attributes
6
+ {
7
+ hide_from: hide_from,
8
+ key: key,
9
+ value: value
10
+ }
11
+ end
12
+
13
+ class Resource < Cornerstore::Resource::Base
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ class Cornerstore::Image < Cornerstore::Model::Base
2
+ attr_accessor :cover,
3
+ :size,
4
+ :format,
5
+ :height,
6
+ :width,
7
+ :key
8
+
9
+
10
+ alias content_type format
11
+ alias file_size size
12
+
13
+ # small, small_square, medium, medium_square, large
14
+ def url(w = 600, h = 600, mode = 'crop')
15
+ "http://res.cloudinary.com/hgzhd1stm/image/upload/c_#{mode},h_#{h},w_#{w}/#{self.key}"
16
+ end
17
+
18
+ class Resource < Cornerstore::Resource::Base
19
+ end
20
+ end
@@ -0,0 +1,74 @@
1
+ class Cornerstore::LineItem < Cornerstore::Model::Base
2
+ include Cornerstore::Model::Writable
3
+
4
+ attr_accessor :order_number,
5
+ :description,
6
+ :qty,
7
+ :unit,
8
+ :price,
9
+ :total,
10
+ :weight,
11
+ :properties,
12
+ :product,
13
+ :variant
14
+
15
+ alias cart parent
16
+
17
+ validates :order_number, length: { within: 1..50 }
18
+ validates :description, length: { within: 1..255 }
19
+ validates :qty, numericality: { greater_than: 0, only_integer: true }
20
+ validates :unit, length: { within: 1..20 }
21
+ validates :price, presence: true
22
+ validates :weight, numericality: { greater_than: 0, allow_nil: true }
23
+ validate do
24
+ errors.add(:price, 'Price must be valid') unless price.valid?
25
+ end
26
+
27
+ def initialize(attributes = {}, parent = nil)
28
+ self.price = Cornerstore::Price.new(attributes.delete('price'))
29
+ self.total = Cornerstore::Price.new(attributes.delete('total'))
30
+ self.properties = Cornerstore::Property::Resource.new(self, attributes.delete('properties') || [])
31
+ self.product = Cornerstore::Product.new(attributes.delete('product')) if attributes['product']
32
+ self.variant = Cornerstore::Variant.new(attributes.delete('variant'), self.product) if attributes['variant']
33
+ super
34
+ end
35
+
36
+ def attributes
37
+ {
38
+ order_number: order_number,
39
+ description: description,
40
+ qty: qty,
41
+ unit: unit,
42
+ price: price.attributes,
43
+ weight: weight
44
+ }
45
+ end
46
+
47
+ class Resource < Cornerstore::Resource::Base
48
+ include Cornerstore::Resource::Remote
49
+ include Cornerstore::Resource::Writable
50
+
51
+ def create_from_variant(variant, attr={})
52
+ attributes = {
53
+ variant_id: variant.id,
54
+ product_id: variant.product._id,
55
+ line_item: attr
56
+ }
57
+
58
+ RestClient.post("#{Cornerstore.root_url}/carts/#{@parent.id}/line_items/derive.json", attributes, Cornerstore.headers) do |response, request, result, &block|
59
+ if response.code == 201
60
+ attributes = ActiveSupport::JSON.decode(response)
61
+ line_item = @klass.new(attributes, @parent)
62
+ elsif response.code == 422 and data = ActiveSupport::JSON.decode(response) and data.has_key?('errors')
63
+ line_item = @klass.new(attr, @parent)
64
+ data['errors'].each_pair do |key, messages|
65
+ messages.map { |message| line_item.errors.add(key, message) }
66
+ end
67
+ end
68
+
69
+ push line_item
70
+ line_item
71
+ end
72
+ end
73
+ end
74
+ end