stall 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +45 -0
- data/app/assets/javascripts/stall.coffee +2 -0
- data/app/assets/javascripts/stall/cart-form.coffee +23 -0
- data/app/controllers/stall/application_controller.rb +10 -2
- data/app/controllers/stall/carts_controller.rb +31 -10
- data/app/controllers/stall/checkout/steps_controller.rb +36 -4
- data/app/controllers/stall/checkouts_controller.rb +12 -3
- data/app/controllers/stall/line_items_controller.rb +3 -3
- data/app/controllers/stall/payments_controller.rb +5 -3
- data/app/helpers/stall/add_to_cart_helper.rb +1 -1
- data/app/helpers/stall/checkout_helper.rb +22 -2
- data/app/helpers/stall/payments_helper.rb +8 -0
- data/app/mailers/stall/admin_mailer.rb +11 -0
- data/app/mailers/stall/base_mailer.rb +17 -0
- data/app/mailers/stall/customer_mailer.rb +13 -0
- data/app/models/address.rb +3 -0
- data/app/models/address_ownership.rb +3 -0
- data/app/models/adjustment.rb +3 -0
- data/app/models/cart.rb +3 -0
- data/app/models/customer.rb +3 -0
- data/app/models/line_item.rb +3 -0
- data/app/models/payment.rb +3 -0
- data/app/models/payment_method.rb +3 -0
- data/app/models/product_list.rb +3 -0
- data/app/models/shipment.rb +3 -0
- data/app/models/shipping_method.rb +3 -0
- data/app/models/stall/models.rb +4 -0
- data/app/models/stall/models/address.rb +45 -0
- data/app/models/stall/models/address_ownership.rb +26 -0
- data/app/models/stall/models/adjustment.rb +49 -0
- data/app/models/stall/models/cart.rb +37 -0
- data/app/models/stall/models/customer.rb +18 -0
- data/app/models/stall/models/line_item.rb +57 -0
- data/app/models/stall/models/payment.rb +33 -0
- data/app/models/stall/models/payment_method.rb +18 -0
- data/app/models/stall/models/product_list.rb +147 -0
- data/app/models/stall/models/shipment.rb +29 -0
- data/app/models/stall/models/shipping_method.rb +16 -0
- data/app/services/stall/add_to_cart_service.rb +11 -1
- data/app/services/stall/cart_update_service.rb +26 -0
- data/app/services/stall/payment_notification_service.rb +23 -9
- data/app/services/stall/shipping_fee_calculator_service.rb +13 -2
- data/app/views/checkout/steps/_informations.html.haml +3 -3
- data/app/views/checkout/steps/_payment.html.haml +25 -4
- data/app/views/checkout/steps/_payment_method.html.haml +1 -3
- data/app/views/checkout/steps/_payment_return.html.haml +6 -0
- data/app/views/checkout/steps/_shipping_method.html.haml +1 -1
- data/app/views/stall/admin_mailer/order_paid_email.html.haml +4 -0
- data/app/views/stall/carts/show.html.haml +36 -8
- data/app/views/stall/customer_mailer/order_paid_email.html.haml +8 -0
- data/app/views/stall/line_items/_added.html.haml +1 -1
- data/app/views/stall/shared/mailers/_address.html.haml +18 -0
- data/app/views/stall/shared/mailers/_cart.html.haml +114 -0
- data/config/locales/stall.fr.yml +90 -8
- data/db/migrate/20160304134849_change_all_json_columns_to_jsonb.rb +18 -0
- data/db/migrate/20160307142924_add_state_to_stall_addresses.rb +5 -0
- data/db/migrate/20160308142713_create_adjustments.rb +16 -0
- data/db/migrate/20160309165136_add_identifier_to_stall_product_lists.rb +5 -0
- data/db/migrate/20160316114649_add_data_to_stall_shipments.rb +5 -0
- data/db/migrate/20160317141632_add_state_to_stall_shipments.rb +5 -0
- data/db/migrate/20160629102943_add_active_to_stall_shipping_methods.rb +11 -0
- data/db/migrate/20160629104617_add_active_to_stall_payment_methods.rb +11 -0
- data/db/migrate/20160705110151_add_locale_to_stall_customers.rb +5 -0
- data/lib/generators/stall/checkout/step/templates/step.html.haml.erb +1 -1
- data/lib/generators/stall/checkout/step/templates/step.rb.erb +10 -2
- data/lib/generators/stall/checkout/wizard/templates/wizard.rb.erb +1 -1
- data/lib/generators/stall/install/templates/initializer.rb +85 -1
- data/lib/generators/stall/model/model_generator.rb +27 -0
- data/lib/generators/stall/service/service_generator.rb +39 -0
- data/lib/generators/stall/service/templates/service.rb.erb +16 -0
- data/lib/generators/stall/shipping/calculator/calculator_generator.rb +17 -0
- data/lib/generators/stall/shipping/calculator/templates/calculator.rb.erb +29 -0
- data/lib/stall.rb +4 -0
- data/lib/stall/addressable.rb +28 -2
- data/lib/stall/cart_helper.rb +84 -0
- data/lib/stall/carts_cleaner.rb +46 -0
- data/lib/stall/checkout.rb +2 -0
- data/lib/stall/checkout/informations_checkout_step.rb +3 -5
- data/lib/stall/checkout/payment_checkout_step.rb +3 -0
- data/lib/stall/checkout/payment_return_checkout_step.rb +11 -0
- data/lib/stall/checkout/shipping_method_checkout_step.rb +2 -1
- data/lib/stall/checkout/step.rb +47 -11
- data/lib/stall/checkout/step_form.rb +71 -0
- data/lib/stall/checkout/wizard.rb +15 -5
- data/lib/stall/config.rb +51 -0
- data/lib/stall/engine.rb +24 -2
- data/lib/stall/payable.rb +26 -0
- data/lib/stall/payments.rb +7 -3
- data/lib/stall/payments/config.rb +37 -0
- data/lib/stall/payments/fake_gateway_payment_notification.rb +34 -0
- data/lib/stall/payments/gateway.rb +19 -12
- data/lib/stall/payments/urls_config.rb +40 -0
- data/lib/stall/priceable.rb +7 -0
- data/lib/stall/rails/currency_helper.rb +1 -1
- data/lib/stall/routes.rb +17 -4
- data/lib/stall/sellable.rb +1 -2
- data/lib/stall/shipping.rb +3 -1
- data/lib/stall/shipping/calculator.rb +36 -3
- data/lib/stall/shipping/config.rb +17 -3
- data/lib/stall/shipping/country_weight_table_calculator.rb +1 -1
- data/lib/stall/shipping/free_shipping_calculator.rb +1 -1
- data/lib/stall/utils.rb +2 -2
- data/lib/stall/utils/config_dsl.rb +5 -1
- data/lib/stall/version.rb +1 -1
- data/lib/tasks/stall_tasks.rake +11 -0
- metadata +73 -15
- data/app/assets/javascripts/stall/application.js +0 -13
- data/app/assets/javascripts/stall/carts.js +0 -2
- data/app/helpers/stall/cart_helper.rb +0 -28
- data/app/models/stall/address.rb +0 -5
- data/app/models/stall/address_ownership.rb +0 -8
- data/app/models/stall/cart.rb +0 -31
- data/app/models/stall/customer.rb +0 -8
- data/app/models/stall/line_item.rb +0 -49
- data/app/models/stall/payment.rb +0 -14
- data/app/models/stall/payment_method.rb +0 -7
- data/app/models/stall/product_list.rb +0 -68
- data/app/models/stall/shipment.rb +0 -15
- data/app/models/stall/shipping_method.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0524d2c5e775b699249a9e311d7eb05f2a28329a
|
4
|
+
data.tar.gz: f13ac7bc4efa4013a6cabf3d92214669832b2610
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d25def30d139c976bbcc3c25635bcc4321dc152b008c62ea4b9d64798b6402b0d1715625e14763588ee3b0d23bef7d88c9591bbc230d9b31ad486d3c8d147544
|
7
|
+
data.tar.gz: c4a3e2c50f5770ad510c1cf8dce6329526e8dc3b5c16172960150976d0ea6ad75b3c87cf4f6735f1c345680a685ba6b6caf02c18352fe17610a0439d624fc337
|
data/README.md
CHANGED
@@ -65,6 +65,51 @@ The checkout process is completely flexible and can be overriden easily.
|
|
65
65
|
Please see the Wiki page :
|
66
66
|
[The checkout process](https://github.com/rails-stall/stall/wiki/The-checkout-process)
|
67
67
|
|
68
|
+
|
69
|
+
### Cleaning up aborted carts
|
70
|
+
|
71
|
+
A cart is created for each new visit on the app. You may want to clean
|
72
|
+
aborted carts to avoid the table to grow too big.
|
73
|
+
|
74
|
+
You can setup the provided `rake` task in a cron :
|
75
|
+
|
76
|
+
```bash
|
77
|
+
rake stall:carts:clean
|
78
|
+
```
|
79
|
+
|
80
|
+
#### Configuring what is cleaned in the task
|
81
|
+
|
82
|
+
Two types of aborted carts are cleaned :
|
83
|
+
|
84
|
+
- Empty carts older than 24h
|
85
|
+
- Aborted carts, with products added, older than 2 weeks
|
86
|
+
|
87
|
+
You can configure both delays with the following config in the stall initializer :
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
config.empty_carts_expires_after = 1.day
|
91
|
+
config.aborted_carts_expires_after = 14.days
|
92
|
+
```
|
93
|
+
|
94
|
+
#### Cleaning other types of ProductList
|
95
|
+
|
96
|
+
You can create your own cart classes by extending the `Cart` or `ProductList`
|
97
|
+
model in your app.
|
98
|
+
|
99
|
+
To clean those models, you just need to pass the cart class name to the rake
|
100
|
+
task when calling it. For a `TestCart` model, you'd do :
|
101
|
+
|
102
|
+
```bash
|
103
|
+
rake stall:carts:clean[TestCart]
|
104
|
+
```
|
105
|
+
|
106
|
+
> **Note** : that double-quotes may be needed around the task name to make that
|
107
|
+
syntax work with some shells (e.g. zsh) : `rake "stall:carts:clean[TestCart]"`
|
108
|
+
|
109
|
+
You can also override in your subclass the way that the task retrieves aborted
|
110
|
+
carts by defining a scope or class method `.aborted(options)` where `options`
|
111
|
+
may contain a `:before` option.
|
112
|
+
|
68
113
|
# Licence
|
69
114
|
|
70
115
|
This project rocks and uses MIT-LICENSE.
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Stall.CartForm extends Vertebra.View
|
2
|
+
events:
|
3
|
+
'change [data-quantity-field]': 'formUpdated'
|
4
|
+
'cocoon:after-remove': 'formUpdated'
|
5
|
+
'ajax:success': 'updateSuccess'
|
6
|
+
|
7
|
+
initialize: ->
|
8
|
+
@clean()
|
9
|
+
|
10
|
+
clean: ->
|
11
|
+
@$('[data-cart-update-button]').hide(0)
|
12
|
+
|
13
|
+
formUpdated: (e) ->
|
14
|
+
@$el.submit()
|
15
|
+
|
16
|
+
updateSuccess: (e, resp) ->
|
17
|
+
$form = $(resp).find('[data-cart-form]')
|
18
|
+
@$el.html($form.html())
|
19
|
+
@clean()
|
20
|
+
|
21
|
+
Stall.onDomReady ->
|
22
|
+
if ($cartForm = $('[data-cart-form]')).length
|
23
|
+
new Stall.CartForm(el: $cartForm)
|
@@ -1,13 +1,21 @@
|
|
1
1
|
module Stall
|
2
2
|
class ApplicationController < Stall.config.application_controller_ancestor.constantize
|
3
|
-
|
3
|
+
before_action :set_request_variant
|
4
|
+
layout :set_stall_layout
|
4
5
|
|
5
6
|
private
|
6
7
|
|
8
|
+
def set_request_variant
|
9
|
+
request.variant = :xhr if request.xhr?
|
10
|
+
end
|
11
|
+
|
7
12
|
# Enforce app-level layout by defaulting to the "application" layout if
|
8
13
|
# no parent layout was set before, thus avoiding the "stall/application"
|
9
14
|
# layout to be rendered
|
10
|
-
def
|
15
|
+
def set_stall_layout
|
16
|
+
return false if request.xhr?
|
17
|
+
return Stall.config.default_layout if Stall.config.default_layout
|
18
|
+
|
11
19
|
parent_controller = self.class.ancestors.find do |ancestor|
|
12
20
|
!ancestor.name.match(/^Stall::/)
|
13
21
|
end
|
@@ -1,28 +1,49 @@
|
|
1
1
|
module Stall
|
2
|
-
class CartsController < ApplicationController
|
3
|
-
before_action :load_cart
|
2
|
+
class CartsController < Stall::ApplicationController
|
3
|
+
before_action :load_cart, except: :show
|
4
4
|
|
5
5
|
def show
|
6
|
+
@cart = ProductList.find_by_token(params[:id]) || current_cart
|
6
7
|
end
|
7
8
|
|
8
9
|
def update
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
respond_to do |format|
|
11
|
+
service = Stall::CartUpdateService.new(@cart, cart_params)
|
12
|
+
|
13
|
+
if service.call
|
14
|
+
format.html.xhr do
|
15
|
+
render 'show'
|
16
|
+
end
|
17
|
+
|
18
|
+
format.html.any do
|
19
|
+
flash[:success] = t('stall.carts.flashes.update.success')
|
20
|
+
redirect_to cart_path(@cart)
|
21
|
+
end
|
22
|
+
else
|
23
|
+
format.html.xhr do
|
24
|
+
render 'show'
|
25
|
+
end
|
26
|
+
|
27
|
+
format.html.any do
|
28
|
+
flash[:error] = t('stall.carts.flashes.update.error')
|
29
|
+
render 'show'
|
30
|
+
end
|
31
|
+
end
|
15
32
|
end
|
16
33
|
end
|
17
34
|
|
18
35
|
private
|
19
36
|
|
20
37
|
def load_cart
|
21
|
-
@cart =
|
38
|
+
@cart = ProductList.find_by_token!(params[:id])
|
22
39
|
end
|
23
40
|
|
24
41
|
def cart_params
|
25
|
-
params.require(:cart).permit(
|
42
|
+
params.require(:cart).permit(
|
43
|
+
line_items_attributes: [
|
44
|
+
:id, :quantity, :_destroy
|
45
|
+
]
|
46
|
+
)
|
26
47
|
end
|
27
48
|
end
|
28
49
|
end
|
@@ -3,6 +3,8 @@ module Stall
|
|
3
3
|
class StepsController < Stall::ApplicationController
|
4
4
|
include Stall::CheckoutHelper
|
5
5
|
|
6
|
+
before_action :load_cart
|
7
|
+
before_action :ensure_cart_checkoutable
|
6
8
|
before_action :load_step
|
7
9
|
|
8
10
|
def show
|
@@ -12,21 +14,51 @@ module Stall
|
|
12
14
|
def update
|
13
15
|
if @step.process
|
14
16
|
@wizard.validate_current_step!
|
15
|
-
redirect_to step_path
|
17
|
+
redirect_to step_path
|
16
18
|
else
|
17
19
|
@step.prepare
|
18
|
-
flash[:error]
|
20
|
+
flash[:error] ||= t("stall.checkout.#{ @wizard.current_step_name }.error")
|
21
|
+
render 'show'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def change
|
26
|
+
target_step = params[:step]
|
27
|
+
|
28
|
+
if @wizard.step_complete?(target_step)
|
29
|
+
@wizard.move_to_step!(target_step)
|
30
|
+
redirect_to step_path
|
31
|
+
else
|
32
|
+
@step.prepare
|
33
|
+
flash[:error] ||= t("stall.checkout.#{ target_step }.error")
|
19
34
|
render 'show'
|
20
35
|
end
|
21
36
|
end
|
22
37
|
|
23
38
|
private
|
24
39
|
|
40
|
+
def load_cart
|
41
|
+
@cart = current_cart
|
42
|
+
end
|
43
|
+
|
44
|
+
def ensure_cart_checkoutable
|
45
|
+
unless @cart.checkoutable?
|
46
|
+
flash[:error] = t('stall.checkout.shared.not_checkoutable')
|
47
|
+
redirect_to request.referrer || root_path
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
25
51
|
def load_step
|
26
|
-
@cart = Stall::Cart.find_by_token(params[:cart_id])
|
27
52
|
@wizard = @cart.wizard.new(@cart)
|
28
53
|
|
29
|
-
@step = @wizard.initialize_current_step
|
54
|
+
@step = @wizard.initialize_current_step do |step|
|
55
|
+
# Inject request dependent data
|
56
|
+
step.inject(:params, params)
|
57
|
+
step.inject(:session, session)
|
58
|
+
step.inject(:cookies, cookies)
|
59
|
+
step.inject(:request, request)
|
60
|
+
step.inject(:flash, flash)
|
61
|
+
|
30
62
|
if Stall.config.steps_initialization
|
31
63
|
instance_exec(step, &Stall.config.steps_initialization)
|
32
64
|
end
|
@@ -1,9 +1,18 @@
|
|
1
1
|
module Stall
|
2
|
-
class CheckoutsController < ApplicationController
|
2
|
+
class CheckoutsController < Stall::ApplicationController
|
3
|
+
include CheckoutHelper
|
4
|
+
|
5
|
+
before_action :load_cart
|
6
|
+
|
3
7
|
def show
|
4
|
-
@cart = Stall::Cart.find_by_token(params[:id])
|
5
8
|
@cart.reset_state!
|
6
|
-
redirect_to
|
9
|
+
redirect_to step_path
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def load_cart
|
15
|
+
@cart = current_cart
|
7
16
|
end
|
8
17
|
end
|
9
18
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Stall
|
2
|
-
class LineItemsController < ApplicationController
|
2
|
+
class LineItemsController < Stall::ApplicationController
|
3
3
|
def create
|
4
|
-
service = Stall
|
4
|
+
service = Stall.config.service_for(:add_to_cart).new(cart, line_item_params)
|
5
5
|
|
6
6
|
if service.call
|
7
7
|
@quantity = params[:line_item][:quantity].to_i
|
@@ -20,7 +20,7 @@ module Stall
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def cart
|
23
|
-
@cart ||=
|
23
|
+
@cart ||= ProductList.find_by_token(params[:cart_id]) || current_cart
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
module Stall
|
2
|
-
class PaymentsController < ApplicationController
|
3
|
-
|
4
|
-
|
2
|
+
class PaymentsController < Stall::ApplicationController
|
3
|
+
skip_before_action :verify_authenticity_token, only: [:notify]
|
4
|
+
|
5
|
+
def notify
|
6
|
+
service = Stall.config.service_for(:payment_notification).new(params[:gateway], request)
|
5
7
|
service.call
|
6
8
|
render service.rendering_options
|
7
9
|
end
|
@@ -1,7 +1,27 @@
|
|
1
1
|
module Stall
|
2
2
|
module CheckoutHelper
|
3
|
-
def step_path(
|
4
|
-
checkout_step_path(
|
3
|
+
def step_path(*args)
|
4
|
+
checkout_step_path(*([current_cart_key] + args))
|
5
|
+
end
|
6
|
+
|
7
|
+
def available_shipping_methods_for(cart)
|
8
|
+
ShippingMethod.active.ordered.select do |shipping_method|
|
9
|
+
calculator_class = Stall::Shipping::Calculator.for(shipping_method)
|
10
|
+
|
11
|
+
unless calculator_class
|
12
|
+
raise Stall::Shipping::CalculatorNotFound,
|
13
|
+
"No calculator found for the shipping method : " +
|
14
|
+
"#{ shipping_method.name } " +
|
15
|
+
"(#{ shipping_method.identifier }). " +
|
16
|
+
"Please remove the Stall::ShippingMethod with id " +
|
17
|
+
"#{ shipping_method.id } or create the associated " +
|
18
|
+
"calculator with `rails g stall:shipping:calculator " +
|
19
|
+
"#{ shipping_method.identifier }`"
|
20
|
+
end
|
21
|
+
|
22
|
+
calculator = calculator_class.new(cart, shipping_method)
|
23
|
+
calculator.available?
|
24
|
+
end
|
5
25
|
end
|
6
26
|
end
|
7
27
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Stall
|
2
|
+
class AdminMailer < Stall::BaseMailer
|
3
|
+
def order_paid_email(cart)
|
4
|
+
@cart = cart
|
5
|
+
|
6
|
+
mail from: sender_email_for(cart),
|
7
|
+
to: admin_email_for(cart),
|
8
|
+
subject: I18n.t('stall.mailers.admin.order_paid_email.subject', ref: cart.reference)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Stall
|
2
|
+
class BaseMailer < Stall.config.mailers_parent_class.constantize
|
3
|
+
private
|
4
|
+
|
5
|
+
def sender_email_for(cart)
|
6
|
+
value_for(Stall.config.sender_email, cart)
|
7
|
+
end
|
8
|
+
|
9
|
+
def admin_email_for(cart)
|
10
|
+
value_for(Stall.config.admin_email, cart)
|
11
|
+
end
|
12
|
+
|
13
|
+
def value_for(config, cart)
|
14
|
+
Proc === config ? config.call(cart) : config
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Stall
|
2
|
+
class CustomerMailer < Stall::BaseMailer
|
3
|
+
def order_paid_email(cart)
|
4
|
+
I18n.with_locale(cart.customer.locale) do
|
5
|
+
@cart = cart
|
6
|
+
|
7
|
+
mail from: sender_email_for(cart),
|
8
|
+
to: cart.customer.email,
|
9
|
+
subject: I18n.t('stall.mailers.customer.order_paid_email.subject', ref: cart.reference)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/app/models/cart.rb
ADDED