stall 0.1.1 → 0.1.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.
- 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