locomotive_ecommerce_plugin 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/Gemfile +40 -0
- data/app/assets/javascripts/locomotive/ecommerce/application.js +15 -0
- data/app/assets/stylesheets/locomotive/ecommerce/application.css +13 -0
- data/app/assets/stylesheets/locomotive/ecommerce/flash_dance.alerts.bootstrap.css +107 -0
- data/app/controllers/locomotive/ecommerce/application_controller.rb +35 -0
- data/app/controllers/locomotive/ecommerce/cart_controller.rb +12 -0
- data/app/controllers/locomotive/ecommerce/order_controller.rb +18 -0
- data/app/controllers/locomotive/ecommerce/purchase_controller.rb +56 -0
- data/app/helpers/locomotive/ecommerce/ecommerce_cart_helper.rb +11 -0
- data/app/helpers/locomotive/ecommerce/ecommerce_helper.rb +25 -0
- data/app/helpers/locomotive/ecommerce/ecommerce_url_helper.rb +52 -0
- data/app/mailers/locomotive/ecommerce/purchase_mailer.rb +19 -0
- data/app/models/locomotive/ecommerce/cart.rb +162 -0
- data/app/models/locomotive/ecommerce/order.rb +100 -0
- data/app/models/locomotive/ecommerce/purchase.rb +148 -0
- data/app/views/flash_dance/_alert.html.erb +4 -0
- data/app/views/flash_dance/_error.html.erb +4 -0
- data/app/views/flash_dance/_info.html.erb +4 -0
- data/app/views/flash_dance/_notice.html.erb +4 -0
- data/app/views/flash_dance/_success.html.erb +4 -0
- data/app/views/flash_dance/_warning.html.erb +4 -0
- data/app/views/kaminari/_first_page.html.erb +11 -0
- data/app/views/kaminari/_gap.html.erb +8 -0
- data/app/views/kaminari/_last_page.html.erb +11 -0
- data/app/views/kaminari/_next_page.html.erb +11 -0
- data/app/views/kaminari/_page.html.erb +12 -0
- data/app/views/kaminari/_paginator.html.erb +23 -0
- data/app/views/kaminari/_prev_page.html.erb +11 -0
- data/app/views/locomotive/ecommerce/purchase_mailer/purchase_confirmation.text.erb +11 -0
- data/config/initializers/active_resource.rb +1 -0
- data/config/initializers/kaminari_config.rb +16 -0
- data/config/initializers/liquid_stack_trace.rb +7 -0
- data/config/initializers/stripe_setup.rb +40 -0
- data/config/routes.rb +14 -0
- data/lib/locomotive/ecommerce/plugin.rb +74 -0
- data/lib/locomotive/ecommerce/plugin/config.html +111 -0
- data/lib/locomotive/ecommerce/plugin/ecommerce_drop.rb +106 -0
- data/lib/locomotive/ecommerce/plugin/ecommerce_filters.rb +35 -0
- data/lib/locomotive/ecommerce/plugin/ecommerce_tags.rb +31 -0
- data/lib/locomotive/ecommerce/plugin/engine.rb +42 -0
- data/lib/locomotive/ecommerce/plugin/inventory_interface.rb +15 -0
- data/lib/locomotive/ecommerce/plugin/version.rb +5 -0
- data/lib/locomotive_ecommerce_plugin.rb +1 -0
- metadata +184 -0
data/config/routes.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Locomotive::Ecommerce::Engine.routes.draw do
|
2
|
+
resources :cart, :only => [:update]
|
3
|
+
resources :checkout, :controller => "purchase",
|
4
|
+
:only => [:create, :update]
|
5
|
+
|
6
|
+
match "add_to_cart/:product_id" => "order#create",
|
7
|
+
:via => :post, :as => "add_to_cart"
|
8
|
+
match "remove_from_cart/:product_id" => "order#destroy",
|
9
|
+
:via => :delete, :as => "remove_from_cart"
|
10
|
+
match "push_orders" => "purchase#push",
|
11
|
+
:via => :get, :as => "push_orders"
|
12
|
+
|
13
|
+
mount StripeHelper::Engine => "/"
|
14
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'locomotive_plugins'
|
4
|
+
require "locomotive/ecommerce/plugin/engine"
|
5
|
+
require 'locomotive/ecommerce/plugin/ecommerce_drop'
|
6
|
+
require 'locomotive/ecommerce/plugin/ecommerce_tags'
|
7
|
+
require 'locomotive/ecommerce/plugin/ecommerce_filters'
|
8
|
+
require 'locomotive/ecommerce/plugin/inventory_interface'
|
9
|
+
require 'cells'
|
10
|
+
require 'kaminari'
|
11
|
+
require 'stripe_helper'
|
12
|
+
|
13
|
+
module Locomotive
|
14
|
+
module Ecommerce
|
15
|
+
class PluginHelper
|
16
|
+
end
|
17
|
+
|
18
|
+
class Plugin
|
19
|
+
include Locomotive::Plugin
|
20
|
+
include ::Locomotive::Ecommerce::InventoryInterface
|
21
|
+
|
22
|
+
before_page_render :set_config
|
23
|
+
|
24
|
+
def self.default_plugin_id
|
25
|
+
'ecommerce'
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.rack_app
|
29
|
+
Engine
|
30
|
+
end
|
31
|
+
|
32
|
+
def config_template_file
|
33
|
+
File.join(File.dirname(__FILE__), 'plugin', 'config.html')
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_liquid
|
37
|
+
@drop ||= EcommerceDrop.new(self)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.liquid_tags
|
41
|
+
{
|
42
|
+
stripe: StripeTag
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.liquid_filters
|
47
|
+
EcommerceFilters
|
48
|
+
end
|
49
|
+
|
50
|
+
def helper
|
51
|
+
if !@helper
|
52
|
+
@helper = PluginHelper.new
|
53
|
+
@helper.instance_eval { extend EcommerceHelper }
|
54
|
+
end
|
55
|
+
return @helper
|
56
|
+
end
|
57
|
+
|
58
|
+
def path
|
59
|
+
rack_app_full_path('/')
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
private
|
64
|
+
def set_config
|
65
|
+
mounted_rack_app.config_hash = config
|
66
|
+
|
67
|
+
::Stripe.api_key = mounted_rack_app.config_or_default('stripe_secret')
|
68
|
+
::StripeHelper.configure do |config|
|
69
|
+
config.public_key = mounted_rack_app.config_or_default('stripe_public')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
<li>
|
2
|
+
<label name="stripe_secret">Stripe Secret Key:</label>
|
3
|
+
<input type="text" name="stripe_secret" />
|
4
|
+
</li>
|
5
|
+
<li>
|
6
|
+
<label name="stripe_public">Stripe Public Key:</label>
|
7
|
+
<input type="text" name="stripe_public" />
|
8
|
+
</li>
|
9
|
+
<li>
|
10
|
+
<label name="cart_url">Cart URL:</label>
|
11
|
+
<input type="text" name="cart_url" />
|
12
|
+
</li>
|
13
|
+
|
14
|
+
<li>
|
15
|
+
<label name="checkout_url">Checkout URL:</label>
|
16
|
+
<input type="text" name="checkout_url" />
|
17
|
+
</li>
|
18
|
+
|
19
|
+
<li>
|
20
|
+
<label name="new_checkout_url">Post Checkout URL:</label>
|
21
|
+
<input type="text" name="post_checkout_url" />
|
22
|
+
</li>
|
23
|
+
<li>
|
24
|
+
<label name="purchases_url">Purchases URL:</label>
|
25
|
+
<input type="text" name="purchases_url" />
|
26
|
+
</li>
|
27
|
+
<li>
|
28
|
+
<label name="with_quantity">Only in Stock Items:</label>
|
29
|
+
<input type="checkbox" name="with_quantity" />
|
30
|
+
</li>
|
31
|
+
<li>
|
32
|
+
<label name="purchases_url">Estimated Tax Rate (in percent):</label>
|
33
|
+
<input type="text" name="estimated_tax_rate" />
|
34
|
+
<p class="inline-hints">Default: 15</p>
|
35
|
+
</li>
|
36
|
+
<li>
|
37
|
+
<label name="tax_model">Tax Model:</label>
|
38
|
+
<select name="tax_model">
|
39
|
+
{{#each content_types}}
|
40
|
+
<option value="{{ this.slug }}">{{ this.name }}</option>
|
41
|
+
{{/each}}
|
42
|
+
</select>
|
43
|
+
<p class="inline-hints">Slug of the model recording tax rates.</p>
|
44
|
+
</li>
|
45
|
+
<li>
|
46
|
+
<label name="country_slug">Country Code Slug:</label>
|
47
|
+
<input type="text" name="country_slug" />
|
48
|
+
</li>
|
49
|
+
<li>
|
50
|
+
<label name="province_slug">Province/State Code Slug:</label>
|
51
|
+
<input type="text" name="province_slug" />
|
52
|
+
</li>
|
53
|
+
<li>
|
54
|
+
<label name="precentage_slug">Precentage Slug:</label>
|
55
|
+
<input type="text" name="precentage_slug" />
|
56
|
+
</li>
|
57
|
+
<li>
|
58
|
+
<label name="shipping_model">Shipping Model:</label>
|
59
|
+
<select name="shipping_model">
|
60
|
+
{{#each content_types}}
|
61
|
+
<option value="{{ this.slug }}">{{ this.name }}</option>
|
62
|
+
{{/each}}
|
63
|
+
</select>
|
64
|
+
<p class="inline-hints">Slug of the model recording shipping rates.</p>
|
65
|
+
</li>
|
66
|
+
<li>
|
67
|
+
<label name="shipping_name_slug">Name Slug:</label>
|
68
|
+
<input type="text" name="shipping_name_slug" />
|
69
|
+
<p class="inline-hints">Default: name</p>
|
70
|
+
</li>
|
71
|
+
<li>
|
72
|
+
<label name="shipping_over_slug">Over Price Break Slug:</label>
|
73
|
+
<input type="text" name="shipping_over_slug" />
|
74
|
+
<p class="inline-hints">Default: over</p>
|
75
|
+
</li>
|
76
|
+
<li>
|
77
|
+
<label name="shipping_under_slug">Under Price Break Slug:</label>
|
78
|
+
<input type="text" name="shipping_under_slug" />
|
79
|
+
<p class="inline-hints">Default: under</p>
|
80
|
+
</li>
|
81
|
+
<li>
|
82
|
+
<label name="price_break">Price Break</label>
|
83
|
+
<input type="text" name="price_break" />
|
84
|
+
<p class="inline-hints">Default: 100</p>
|
85
|
+
</li>
|
86
|
+
<li>
|
87
|
+
<label name="edit_extra">Apply extras</label>
|
88
|
+
<textarea type="text" style="height=400px" name="edit_extra" />
|
89
|
+
<p class="inline-hints">Use Javascript to integrate extra charges to total price.</p>
|
90
|
+
</li>
|
91
|
+
<li>
|
92
|
+
<label name="shop_name">Shop Name</label>
|
93
|
+
<input type="text" name="shop_name" />
|
94
|
+
</li>
|
95
|
+
<li>
|
96
|
+
<label name="remote_order">After Purchase Complete JS3</label>
|
97
|
+
<textarea style="height=400px" type="text" name="after_purchase_hook" />
|
98
|
+
<p class="inline-hints">JS3 that will be run after a purchase has been completer</p>
|
99
|
+
</li>
|
100
|
+
<li>
|
101
|
+
<label name="shop_inventory_update">Shop Inventory Items</label>
|
102
|
+
<input type="text" name="shop_inventory_update" />
|
103
|
+
</li>
|
104
|
+
<li>
|
105
|
+
<label name="shop_inventory_items">Shop Inventory Items Class</label>
|
106
|
+
<input type="text" name="shop_inventory_items" />
|
107
|
+
</li>
|
108
|
+
<li>
|
109
|
+
<label name="contact">Contact</label>
|
110
|
+
<input type="text" name="contact" />
|
111
|
+
</li>
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Ecommerce
|
3
|
+
class EcommerceDrop < ::Liquid::Drop
|
4
|
+
def initialize(source)
|
5
|
+
@source = source
|
6
|
+
urls = ['cart_url', 'checkout_url', 'new_checkout_url', 'product_url',
|
7
|
+
'products_url', 'purchases_url']
|
8
|
+
urls.each do |name|
|
9
|
+
self.class.send(:define_method, name) do
|
10
|
+
source.mounted_rack_app.config_or_default(name)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def products
|
16
|
+
search_filter(source.inventory_items)
|
17
|
+
end
|
18
|
+
|
19
|
+
def show_out_of_stock?
|
20
|
+
!!Engine.config_or_default('with_quantity')
|
21
|
+
end
|
22
|
+
|
23
|
+
def cart
|
24
|
+
unless @cart
|
25
|
+
session = @context.registers[:controller].session
|
26
|
+
site = Thread.current[:site]
|
27
|
+
user_from_plugin = site.plugin_object_for_id('identity_plugin').js3_context['identity_plugin_users']
|
28
|
+
user = user_from_plugin.where(id: session[:user_id]).first
|
29
|
+
id = user == nil ? nil : user.id
|
30
|
+
@cart = Cart.find_or_create(id, session)
|
31
|
+
end
|
32
|
+
@cart
|
33
|
+
end
|
34
|
+
|
35
|
+
def purchase
|
36
|
+
unless @purchase
|
37
|
+
session = @context.registers[:controller].session
|
38
|
+
site = Thread.current[:site]
|
39
|
+
user_from_plugin = site.plugin_object_for_id('identity_plugin').js3_context['identity_plugin_users']
|
40
|
+
user = user_from_plugin.where(id: session[:user_id]).first
|
41
|
+
puts "Count in Drop 1: #{Purchase.count}"
|
42
|
+
@purchase = cart.purchase || Purchase.new
|
43
|
+
cart.purchase = @purchase
|
44
|
+
cart.save!
|
45
|
+
@purchase.save!
|
46
|
+
puts "Count in Drop 2: #{Purchase.count}"
|
47
|
+
end
|
48
|
+
@purchase
|
49
|
+
end
|
50
|
+
|
51
|
+
def purchases
|
52
|
+
session = @context.registers[:controller].session
|
53
|
+
site = Thread.current[:site]
|
54
|
+
user_from_plugin = site.plugin_object_for_id('identity_plugin').js3_context['identity_plugin_users']
|
55
|
+
user = user_from_plugin.where(id: session[:user_id]).first
|
56
|
+
Purchase.where(user_id: user.id).all.to_a
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
attr_reader :source
|
61
|
+
|
62
|
+
def search_filter(products)
|
63
|
+
params = @context['params']
|
64
|
+
whitelist = {
|
65
|
+
'sku' => :sku,
|
66
|
+
'product' => :description,
|
67
|
+
'price' => :price,
|
68
|
+
'quantity' => :quantity,
|
69
|
+
'vendor' => :vendor,
|
70
|
+
'group' => :group,
|
71
|
+
'dcs' => :category
|
72
|
+
}
|
73
|
+
|
74
|
+
params.each do |k,v|
|
75
|
+
k_split = k.split('_')
|
76
|
+
last = k_split.size > 1 ? k_split.delete_at(-1) : nil
|
77
|
+
first = k_split.join('_')
|
78
|
+
next if !whitelist.key? first
|
79
|
+
field = whitelist[first].to_sym
|
80
|
+
if last == nil
|
81
|
+
if field == :category
|
82
|
+
v.split(' ').each do |value|
|
83
|
+
regex = /^#{Regexp.escape(value)}.*/i
|
84
|
+
products = products.or(category: regex)
|
85
|
+
end
|
86
|
+
else
|
87
|
+
regex = /#{Regexp.escape(v)}/i
|
88
|
+
products = products.and(field => regex)
|
89
|
+
end
|
90
|
+
elsif last == 'min'
|
91
|
+
products = products.and(field.gt => v)
|
92
|
+
elsif last == 'max'
|
93
|
+
products = products.and(field.lt => v)
|
94
|
+
elsif last == 'sort'
|
95
|
+
if v == 'asc'
|
96
|
+
products = products.asc(field)
|
97
|
+
elsif v == 'desc'
|
98
|
+
products = products.desc(field)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
products
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Ecommerce
|
3
|
+
module EcommerceFilters
|
4
|
+
|
5
|
+
def cart_update_path(cart)
|
6
|
+
stem = @context.registers[:plugin_object].path
|
7
|
+
"#{stem}cart/#{cart.id}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_to_cart_path(product)
|
11
|
+
stem = @context.registers[:plugin_object].path
|
12
|
+
"#{stem}add_to_cart/#{product.id}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def remove_from_cart_path(product_sku)
|
16
|
+
stem = @context.registers[:plugin_object].path
|
17
|
+
"#{stem}remove_from_cart/#{product_sku}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def checkout_path(purchase)
|
21
|
+
stem = @context.registers[:plugin_object].path
|
22
|
+
"#{stem}checkout"
|
23
|
+
end
|
24
|
+
|
25
|
+
def checkout_update_path(purchase)
|
26
|
+
stem = @context.registers[:plugin_object].path
|
27
|
+
"#{stem}checkout/#{purchase.id}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_purchase(id)
|
31
|
+
Purchase.find(id.to_s)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Ecommerce
|
3
|
+
module EcommerceTagHelper
|
4
|
+
def render(context)
|
5
|
+
@plugin_obj = context.registers[:plugin_object]
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class StripeTag < ::Liquid::Tag
|
10
|
+
include EcommerceTagHelper
|
11
|
+
def render(context)
|
12
|
+
super
|
13
|
+
session = context.registers[:controller].session
|
14
|
+
site = Thread.current[:site]
|
15
|
+
user_from_plugin = site.plugin_object_for_id('identity_plugin').js3_context['identity_plugin_users']
|
16
|
+
user = user_from_plugin.find(session[:user_id])
|
17
|
+
# user = IdentityPlugin::User.find(session[:user_id])
|
18
|
+
id = user == nil ? nil : user.id
|
19
|
+
cart = Cart.find_or_create(id, session)
|
20
|
+
@purchase = cart.purchase
|
21
|
+
context.registers[:controller].render_cell 'stripe_helper/stripe', :show,
|
22
|
+
amount: (@purchase.total.round(2) * 100).to_i,
|
23
|
+
desc: Date.today,
|
24
|
+
pk: StripeHelper.config.public_key,
|
25
|
+
stem: @plugin_obj.path,
|
26
|
+
store: Engine.config_or_default('shop_name'),
|
27
|
+
token: @purchase.id
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#require 'omniauth-identity'
|
2
|
+
|
3
|
+
module Locomotive
|
4
|
+
module Ecommerce
|
5
|
+
class Engine < ::Rails::Engine
|
6
|
+
# would this change to Locomotive::Ecommerce?
|
7
|
+
isolate_namespace Ecommerce
|
8
|
+
|
9
|
+
def self.config_hash=(hash)
|
10
|
+
@config_hash = hash
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.config_hash
|
14
|
+
@config_hash ||= {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.config_or_default(key)
|
18
|
+
defaults = {
|
19
|
+
'cart_url' => '/cart',
|
20
|
+
'checkout_url' => '/checkout',
|
21
|
+
'post_checkout_url' => '/complete',
|
22
|
+
'confirm_order_url' => '/confirm',
|
23
|
+
'purchases_url' => '/purchases',
|
24
|
+
'estimated_tax_rate' => '15',
|
25
|
+
'country_slug' => 'country',
|
26
|
+
'province_slug' => 'province',
|
27
|
+
'precentage_slug' => 'precentage',
|
28
|
+
'shipping_name_slug' => 'name',
|
29
|
+
'shipping_over_slug' => 'over',
|
30
|
+
'shipping_under_slug' => 'under',
|
31
|
+
'price_break' => '100',
|
32
|
+
'edit_extra' => 'add extras through JS',
|
33
|
+
'shop_name' => "<insert name>",
|
34
|
+
'shop_inventory' => "inventory_itemsUpdate",
|
35
|
+
'contact' => "fake@email.com"
|
36
|
+
}
|
37
|
+
hash = defaults.merge(config_hash)
|
38
|
+
hash[key]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Locomotive
|
2
|
+
module Ecommerce
|
3
|
+
module InventoryInterface
|
4
|
+
# Inventory
|
5
|
+
def inventory_items
|
6
|
+
site = Thread.current[:site]
|
7
|
+
site.plugin_object_for_id('inventory').js3_context.eval(Engine.config_or_default('shop_inventory_update'))
|
8
|
+
end
|
9
|
+
def inventory_items_class
|
10
|
+
site = Thread.current[:site]
|
11
|
+
site.plugin_object_for_id('inventory').js3_context.eval(Engine.config_or_default('shop_inventory_items'))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'locomotive/ecommerce/plugin'
|