stall 0.1.3 → 0.2.0

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -3
  3. data/app/assets/javascripts/stall/add-to-cart-form.coffee +55 -3
  4. data/app/assets/javascripts/stall/addresses-fields.coffee +17 -0
  5. data/app/assets/javascripts/stall/remote-sign-in-form.coffee +55 -0
  6. data/app/assets/javascripts/stall.coffee +3 -1
  7. data/app/controllers/stall/application_controller.rb +1 -1
  8. data/app/controllers/stall/carts_controller.rb +1 -3
  9. data/app/controllers/stall/checkout/steps_controller.rb +18 -1
  10. data/app/helpers/stall/checkout_helper.rb +7 -8
  11. data/app/helpers/stall/customers_helper.rb +25 -0
  12. data/app/models/stall/models/cart.rb +2 -0
  13. data/app/models/stall/models/customer.rb +20 -0
  14. data/app/models/stall/models/product_list.rb +13 -0
  15. data/app/views/checkout/steps/_informations.html.haml +24 -35
  16. data/app/views/checkout/steps/_payment.html.haml +1 -45
  17. data/app/views/checkout/steps/_shipping_method.html.haml +0 -1
  18. data/app/views/stall/addresses/_fields.html.haml +16 -0
  19. data/app/views/stall/addresses/_nested_fields.html.haml +14 -0
  20. data/app/views/stall/carts/_cart.html.haml +45 -0
  21. data/app/views/stall/carts/show.html.haml +2 -2
  22. data/app/views/stall/customers/_fields.html.haml +32 -0
  23. data/app/views/stall/customers/_sign_in.html.haml +20 -0
  24. data/app/views/stall/line_items/_form.html.haml +2 -2
  25. data/app/views/stall/payments/_fields.html.haml +2 -0
  26. data/app/views/stall/shared/mailers/_cart.html.haml +31 -29
  27. data/app/views/stall/shipments/_fields.html.haml +2 -0
  28. data/config/locales/stall.fr.yml +35 -8
  29. data/lib/generators/stall/checkout/step/templates/step.rb.erb +9 -0
  30. data/lib/generators/stall/checkout/wizard/templates/wizard.rb.erb +1 -1
  31. data/lib/generators/stall/install/install_generator.rb +6 -0
  32. data/lib/generators/stall/install/templates/initializer.rb +10 -1
  33. data/lib/generators/stall/view/view_generator.rb +38 -0
  34. data/lib/stall/addressable.rb +2 -0
  35. data/lib/stall/addresses/copier_base.rb +24 -0
  36. data/lib/stall/addresses/copy_source_to_target.rb +45 -0
  37. data/lib/stall/addresses/prefill_target_from_source.rb +29 -0
  38. data/lib/stall/addresses.rb +9 -0
  39. data/lib/stall/cart_helper.rb +14 -1
  40. data/lib/stall/checkout/informations_checkout_step.rb +133 -14
  41. data/lib/stall/checkout/payment_checkout_step.rb +21 -1
  42. data/lib/stall/checkout/step.rb +22 -15
  43. data/lib/stall/checkout/step_form.rb +22 -8
  44. data/lib/stall/config.rb +17 -3
  45. data/lib/stall/engine.rb +6 -0
  46. data/lib/stall/payable.rb +9 -0
  47. data/lib/stall/payments/gateway.rb +16 -6
  48. data/lib/stall/payments/urls_config.rb +2 -2
  49. data/lib/stall/rails/routing_mapper.rb +4 -6
  50. data/lib/stall/routes.rb +4 -1
  51. data/lib/stall/sellable.rb +13 -3
  52. data/lib/stall/version.rb +1 -1
  53. data/lib/stall.rb +1 -0
  54. metadata +25 -6
  55. data/lib/stall/checkout/payment_method_checkout_step.rb +0 -9
  56. data/lib/stall/checkout/shipping_method_checkout_step.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 93101cd6c71bd164e54d7f7a96009894eaee815d
4
- data.tar.gz: e9e552e25b8fa6a49ac0423cacac158b267585ab
3
+ metadata.gz: 282c715e0c37f5b8581b410bcc70a30777973284
4
+ data.tar.gz: cc5283aa96ce4dd6cbb89678fc1ef73a812be26d
5
5
  SHA512:
6
- metadata.gz: ad0c5c29e895dcadf8aff1631374685f209ce73db2e6c28ff313648e33c67093dbb0fbef762d34abcaaf9b3eb4f015a6a151285b47f8327fb194c3e162f0dfa1
7
- data.tar.gz: ad331dadf79752be6c13933ef96060aa07c4b7ae5ebbea33f42757d2160bfb10825d30c2f6dbe0092d91edb1df82abbb419bc8e55f3b5583274bd889a1b3e7ad
6
+ metadata.gz: 256db2643c7db87598b7c55f6101b4c88b180ce7b27b17cb6d2596230cd36077b48265ef0b07e7b1c7cd8a5c45ce0addc58b5198fce5768075086c20bd02c6d7
7
+ data.tar.gz: 1cb10a57017e254f1fcabdf2e57e613fda6b1aee3f0392a74e0d7d7932eb4062554eae49e2100dc29f68940365da710b82192d1da67fe7322519cbd2af1e61f1
data/README.md CHANGED
@@ -38,7 +38,16 @@ This will generate :
38
38
 
39
39
  ## Usage
40
40
 
41
- ### Making a model sellable
41
+ In the following sections, you'll find the following informations :
42
+
43
+ 1. [Making a model sellable](#1--Making-a-model-sellable)
44
+ 2. [Configuring shop defaults](#2--Configuring-shop-defaults)
45
+ 3. [Configuring the checkout flow](#3--Configuring-the-checkout-flow)
46
+ 4. [Customizing views](#4--Customizing-views)
47
+ 5. [Cleaning up aborted carts](#5--Cleaning-up-aborted-carts)
48
+
49
+
50
+ ### 1. Making a model sellable
42
51
 
43
52
  Stall allows you to make any model sellable by including the `Stall::Sellable`
44
53
  mixin into your model :
@@ -58,7 +67,21 @@ You can now add the "Add to cart" button to your templates :
58
67
  For more informations see the Wiki page :
59
68
  [Allowing customers to add products to cart](https://github.com/rails-stall/stall/wiki/Allowing-customers-to-add-products-to-cart)
60
69
 
61
- ### Configuring the checkout flow
70
+ ### 2. Configuring shop defaults
71
+
72
+ Before running the shop, please read through the generated Stall initializer
73
+ file at `config/initializers/stall.rb` and customize their values to your
74
+ fir your desired shop behavior.
75
+
76
+ Here are the mandatory ones :
77
+
78
+ - `store_name`
79
+ - `admin_email`
80
+ - `sender_email`
81
+ - `default_app_domain`
82
+
83
+
84
+ ### 3. Configuring the checkout flow
62
85
 
63
86
  The checkout process is completely flexible and can be overriden easily.
64
87
 
@@ -66,7 +89,22 @@ Please see the Wiki page :
66
89
  [The checkout process](https://github.com/rails-stall/stall/wiki/The-checkout-process)
67
90
 
68
91
 
69
- ### Cleaning up aborted carts
92
+ ### 4. Customizing views
93
+
94
+ You can copy stall views to your app with the `stall:view` generator.
95
+ The less you customize the views, the more you get it to work with future
96
+ Stall versions.
97
+
98
+ Find the templates you need by browsing the source code (ex: `bundle open stall`)
99
+ and generate the needed views. You can pass any number of views at a time.
100
+
101
+ Example :
102
+
103
+ ```bash
104
+ rails generate stall:view checkout/steps/_informations checkout/steps/_payment stall/carts/_cart
105
+ ```
106
+
107
+ ### 5. Cleaning up aborted carts
70
108
 
71
109
  A cart is created for each new visit on the app. You may want to clean
72
110
  aborted carts to avoid the table to grow too big.
@@ -1,11 +1,40 @@
1
1
  class Stall.AddToCartForm extends Vertebra.View
2
2
  @create = ($el) ->
3
- return if $el.data('stall.add-to-cart-form')
4
- instance = new Stall.AddToCartForm(el: $el)
5
- $el.data('stall.add-to-cart-form', instance)
3
+ unless (instance = $el.data('stall.add-to-cart-form'))
4
+ instance = new Stall.AddToCartForm(el: $el)
5
+ $el.data('stall.add-to-cart-form', instance)
6
+
7
+ instance.sendRequest()
6
8
 
7
9
  events:
8
10
  'ajax:success': 'onSuccess'
11
+ 'ajax:complete': 'onComplete'
12
+ 'change [name$="[sellable_id]"]': 'onValidatableFieldChanged'
13
+ 'change [name$="[quantity]"]': 'onValidatableFieldChanged'
14
+
15
+ initialize: ->
16
+ @$button = @$('[type="submit"]')
17
+ @errorMessages = @$el.data('error-messages')
18
+
19
+ sendRequest: ->
20
+ return false unless @validate(submit: true) and !@errors.length
21
+ @setLoading(true)
22
+ true
23
+
24
+ onValidatableFieldChanged: ->
25
+ @validate()
26
+
27
+ validate: (options = {})->
28
+ @checkErrors()
29
+ @refreshErrorsDisplay(options)
30
+
31
+ checkErrors: ->
32
+ @errors = []
33
+ @errors.push('choose') unless @$('[name$="[sellable_id]"]').val()
34
+ @errors.push('quantity') unless @$('[name$="[quantity]"]').val()
35
+
36
+ onComplete: ->
37
+ @setLoading(false)
9
38
 
10
39
  onSuccess: (e, resp) ->
11
40
  @$modal = $(resp).appendTo('body').modal()
@@ -17,6 +46,29 @@ class Stall.AddToCartForm extends Vertebra.View
17
46
  if ($counter = $('[data-cart-quantity-counter]')).length
18
47
  $counter.text(quantity)
19
48
 
49
+ # Displays errors in a tooltip on the form submit button, listing different
50
+ # errors and disabling the submit button
51
+ refreshErrorsDisplay: (options = {}) ->
52
+ buttonIsTooltip = @$button.data('bs.tooltip')
53
+
54
+ if @errors.length
55
+ messages = (@errorMessages[error] for error in @errors)
56
+ message = messages.join('<br>')
57
+ @$button.attr(title: message)
58
+ @$button.tooltip() unless buttonIsTooltip
59
+ # Force tooltip display if the user just submitted the form
60
+ @$button.tooltip('show') if options.submit
61
+ @$button.prop('disabled', true)
62
+ else
63
+ @$button.attr(title: '')
64
+ @$button.tooltip('destroy') if buttonIsTooltip
65
+ @$button.prop('disabled', false)
66
+
67
+ setLoading: (loading) ->
68
+ state = if loading then 'loading' else 'reset'
69
+ @$button.button(state)
70
+
71
+
20
72
  Stall.onDomReady ->
21
73
  $('body').on 'ajax:beforeSend', '[data-add-to-cart-form]', (e) ->
22
74
  Stall.AddToCartForm.create($(e.currentTarget))
@@ -0,0 +1,17 @@
1
+ class Stall.AddressesFields extends Vertebra.View
2
+ events:
3
+ 'change [data-use-another-address-for-billing]': 'addressesSwitchChanged'
4
+
5
+ initialize: ->
6
+ @refresh()
7
+
8
+ addressesSwitchChanged: ->
9
+ @refresh()
10
+
11
+ refresh: ->
12
+ checked = @$('[data-use-another-address-for-billing]').is(':checked')
13
+ @$('[data-address-form="billing"]').toggleClass('hidden', !checked)
14
+
15
+ Stall.onDomReady ->
16
+ if ($addressesFields = $('[data-addresses-fields]')).length
17
+ new Stall.AddressesFields(el: $addressesFields)
@@ -0,0 +1,55 @@
1
+ # This class handles the sign in form inside the checkout process, allowing the
2
+ # customers to sign in directly during the checkout, without leaving the
3
+ # process.
4
+ #
5
+ class Stall.RemoteSignInForm extends Vertebra.View
6
+ @create = ($el) ->
7
+ unless (instance = $el.data('stall.remote-sign-in-form'))
8
+ instance = new Stall.RemoteSignInForm(el: $el)
9
+ instance.onBeforeSend()
10
+ $el.data('stall.remote-sign-in-form', instance)
11
+
12
+ events:
13
+ 'ajax:beforeSend': 'onBeforeSend'
14
+ 'ajax:success': 'onSuccess'
15
+ 'ajax:error': 'onError'
16
+
17
+ initialize: ->
18
+ # We store the current URL to allow refreshing the page after the user
19
+ # signed in, since Turbolinks 5 automatically forces the browser to follow
20
+ # server redirections by evaluating javascript in the browser. Since we
21
+ # don't want to configure Devise (or other gems) server-side, we work-around
22
+ # this issue by running a second redirection, manually, with the URL we
23
+ # store here
24
+ @currentURL = window.location.href
25
+
26
+ onBeforeSend: ->
27
+ @setLoading(true)
28
+
29
+ onSuccess: (e, response) ->
30
+ @setLoading(false)
31
+ @removeFlashMessage()
32
+ Turbolinks.visit(@currentURL)
33
+
34
+ onError: (e, jqXHR) ->
35
+ @setFlashMessage(jqXHR.responseText, type: 'danger')
36
+ @setLoading(false)
37
+
38
+ setLoading: (loading) ->
39
+ state = if loading then 'loading' else 'reset'
40
+ @$('[data-sign-in-submit-btn]').button(state)
41
+
42
+ setFlashMessage: (message, options = {}) ->
43
+ @removeFlashMessage()
44
+ alertClass = "alert alert-#{ options.type }"
45
+ $('<div/>', class: alertClass, 'data-flash': true)
46
+ .html(message).prependTo(@$el)
47
+
48
+ removeFlashMessage: ->
49
+ @$('[data-flash]').remove()
50
+
51
+
52
+ Stall.onDomReady ->
53
+ $('[data-stall-remote-sign-in-form]').each (i, el) ->
54
+ $(el).one 'ajax:beforeSend', (e) ->
55
+ Stall.RemoteSignInForm.create($(e.currentTarget))
@@ -3,11 +3,13 @@
3
3
  #= require_self
4
4
  #= require stall/add-to-cart-form
5
5
  #= require stall/cart-form
6
+ #= require stall/addresses-fields
7
+ #= require stall/remote-sign-in-form
6
8
 
7
9
  @Stall =
8
10
  onDomReady: (callback) ->
9
11
  event = if window.Turbolinks && window.Turbolinks.supported
10
- 'page:change'
12
+ 'page:change turbolinks:load'
11
13
  else
12
14
  'ready'
13
15
 
@@ -17,7 +17,7 @@ module Stall
17
17
  return Stall.config.default_layout if Stall.config.default_layout
18
18
 
19
19
  parent_controller = self.class.ancestors.find do |ancestor|
20
- !ancestor.name.match(/^Stall::/)
20
+ !ancestor.name.to_s.match(/^Stall::/) && Class === ancestor
21
21
  end
22
22
 
23
23
  parent_controller._layout ||= 'application'
@@ -40,9 +40,7 @@ module Stall
40
40
 
41
41
  def cart_params
42
42
  params.require(:cart).permit(
43
- line_items_attributes: [
44
- :id, :quantity, :_destroy
45
- ]
43
+ line_items_attributes: [:id, :quantity, :_destroy]
46
44
  )
47
45
  end
48
46
  end
@@ -3,6 +3,7 @@ module Stall
3
3
  class StepsController < Stall::ApplicationController
4
4
  include Stall::CheckoutHelper
5
5
 
6
+ skip_before_action :verify_authenticity_token, on: :foreign_update
6
7
  before_action :load_cart
7
8
  before_action :load_step
8
9
  before_action :ensure_cart_checkoutable
@@ -22,6 +23,8 @@ module Stall
22
23
  end
23
24
  end
24
25
 
26
+ alias_method :foreign_update, :update
27
+
25
28
  def change
26
29
  target_step = params[:step]
27
30
 
@@ -53,7 +56,7 @@ module Stall
53
56
 
54
57
  unless @cart.checkoutable?
55
58
  flash[:error] = t('stall.checkout.shared.not_checkoutable')
56
- redirect_to request.referrer || root_path
59
+ redirect_to_referrer_or_root
57
60
  end
58
61
  end
59
62
 
@@ -67,12 +70,26 @@ module Stall
67
70
  step.inject(:cookies, cookies)
68
71
  step.inject(:request, request)
69
72
  step.inject(:flash, flash)
73
+ step.inject(:stall_user_signed_in?, stall_user_signed_in?)
74
+ step.inject(:current_stall_user, current_stall_user)
70
75
 
71
76
  if Stall.config.steps_initialization
72
77
  instance_exec(step, &Stall.config.steps_initialization)
73
78
  end
74
79
  end
75
80
  end
81
+
82
+ def redirect_to_referrer_or_root
83
+ referrer = URI.parse(request.referrer).path if request.referrer
84
+
85
+ redirect_target = if referrer && referrer != request.path
86
+ request.referrer
87
+ else
88
+ root_path
89
+ end
90
+
91
+ redirect_to redirect_target
92
+ end
76
93
  end
77
94
  end
78
95
  end
@@ -9,14 +9,13 @@ module Stall
9
9
  calculator_class = Stall::Shipping::Calculator.for(shipping_method)
10
10
 
11
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 }`"
12
+ raise Stall::Shipping::CalculatorNotFound, <<-MSG.squish
13
+ No calculator found for the shipping method : #{ shipping_method.name }
14
+ (#{ shipping_method.identifier }).
15
+ Please remove the Stall::ShippingMethod with id #{ shipping_method.id }
16
+ or create the associated calculator with
17
+ `rails g stall:shipping:calculator #{ shipping_method.identifier }`
18
+ MSG
20
19
  end
21
20
 
22
21
  calculator = calculator_class.new(cart, shipping_method)
@@ -0,0 +1,25 @@
1
+ module Stall
2
+ module CustomersHelper
3
+ def stall_user_signed_in?
4
+ !!current_stall_user
5
+ end
6
+
7
+ def current_stall_user
8
+ send(Stall.config.default_user_helper_method)
9
+ end
10
+
11
+ # Copy e-mail error messages from user to customer, allowing them to be
12
+ # displayed in customer e-mail input to the visitor
13
+ #
14
+ def with_errors_from_user(customer)
15
+ return customer unless (user = customer.user) && user.errors.any?
16
+ return unless (messages = user.errors.messages[:email]) && messages.any?
17
+
18
+ messages.each do |message|
19
+ customer.errors.add(:email, message)
20
+ end
21
+
22
+ customer
23
+ end
24
+ end
25
+ end
@@ -12,6 +12,8 @@ module Stall
12
12
 
13
13
  has_many :adjustments, dependent: :destroy, inverse_of: :cart
14
14
  accepts_nested_attributes_for :adjustments
15
+
16
+ attr_accessor :terms
15
17
  end
16
18
 
17
19
  def total_weight
@@ -12,6 +12,26 @@ module Stall
12
12
  accepts_nested_attributes_for :user
13
13
 
14
14
  has_many :product_lists, dependent: :destroy
15
+
16
+ validates :email, format: { with: /\A[^@\s]+@([^@\s]+\.)+[^@\W]+\z/ },
17
+ allow_blank: true
18
+
19
+ before_validation :ensure_user_email
20
+
21
+ def user_or_default
22
+ user || build_user
23
+ end
24
+
25
+ def build_user(attributes = {})
26
+ attributes.reverse_merge!(customer: self)
27
+ self.user = Stall.config.default_user_model.new(attributes)
28
+ end
29
+
30
+ private
31
+
32
+ def ensure_user_email
33
+ user.email = email if user && user.email.blank?
34
+ end
15
35
  end
16
36
  end
17
37
  end
@@ -21,6 +21,7 @@ module Stall
21
21
  after_initialize :ensure_currency
22
22
  after_initialize :ensure_state
23
23
 
24
+ before_save :save_customer_if_changed
24
25
  after_save :ensure_reference, on: :create
25
26
 
26
27
  scope :empty, -> {
@@ -90,6 +91,14 @@ module Stall
90
91
  true
91
92
  end
92
93
 
94
+ def currency
95
+ @currency ||= if (currency = read_attribute(:currency).presence)
96
+ Money::Currency.new(currency)
97
+ else
98
+ self.currency = Money.default_currency
99
+ end
100
+ end
101
+
93
102
  private
94
103
 
95
104
  def ensure_currency
@@ -112,6 +121,10 @@ module Stall
112
121
  end
113
122
  end
114
123
 
124
+ def save_customer_if_changed
125
+ customer.save if customer && customer.changed?
126
+ end
127
+
115
128
  module ClassMethods
116
129
  def find_by_reference(reference)
117
130
  where("data->>'reference' = ?", reference).first
@@ -1,41 +1,30 @@
1
+ -# Display sign in form for users that are not signed in
2
+ - unless stall_user_signed_in?
3
+ - resource = Stall.config.default_user_model.new
4
+ = render partial: 'stall/customers/sign_in', locals: { resource: resource, resource_name: resource.model_name.element }
5
+
1
6
  %h1= t('stall.checkout.informations.title')
2
7
 
3
8
  = simple_form_for cart, as: :cart, url: step_path do |form|
4
- = form.fields_for :customer do |customer_form|
5
- = customer_form.input :email
6
-
7
- = form.fields_for :address_ownerships, [cart.address_ownership_for(:shipping)] do |ownership_form|
8
- %fieldset{ data: { :'address-form' => :shipping } }
9
- = ownership_form.hidden_field :shipping
10
-
11
- = ownership_form.fields_for :address do |address_form|
12
- = address_form.input :civility, collection: Address.civility_enum
13
- = address_form.input :first_name
14
- = address_form.input :last_name
15
- = address_form.input :address
16
- = address_form.input :address_details
17
- = address_form.input :zip
18
- = address_form.input :city
19
- = address_form.input :country
20
- = address_form.input :phone
21
-
22
- = form.input :use_another_address_for_billing do
23
- = check_box_tag :use_another_address_for_billing, '1', params[:use_another_address_for_billing]
9
+ .row
10
+ .col-md-7
11
+ = render partial: 'stall/customers/fields', locals: { form: form, cart: cart }
12
+ = render partial: 'stall/addresses/fields', locals: { form: form, cart: cart }
24
13
 
25
- = form.fields_for :address_ownerships, [cart.address_ownership_for(:billing)] do |ownership_form|
26
- %fieldset{ data: { :'address-form' => :billing } }
27
- = ownership_form.hidden_field :billing
14
+ .col-md-5
15
+ = render partial: 'stall/carts/cart', locals: { cart: cart }
16
+ = render partial: 'stall/shipments/fields', locals: { form: form, cart: cart }
17
+ = render partial: 'stall/payments/fields', locals: { form: form, cart: cart }
28
18
 
29
- = ownership_form.fields_for :address do |address_form|
30
- = address_form.input :civility, collection: Address.civility_enum
31
- = address_form.input :first_name
32
- = address_form.input :last_name
33
- = address_form.input :address
34
- = address_form.input :address_details
35
- = address_form.input :zip
36
- = address_form.input :city
37
- = address_form.input :country
38
- = address_form.input :phone
19
+ -# Basic implementation to display the terms acceptance checkbox before
20
+ -# the order is placed. Just fill in the `config.terms_path` in the
21
+ -# Stall initializer if you want to change the terms URL, but feel free
22
+ -# to customize further if needed.
23
+ = form.input :terms, label: false do
24
+ = form.check_box :terms
25
+ = form.label :terms, t('stall.checkout.informations.accept_the')
26
+ = link_to Stall.config.terms_path, target: '_blank' do
27
+ = form.object.class.human_attribute_name(:terms)
39
28
 
40
- %button.btn.btn-primary{ type: 'submit' }
41
- = t('stall.checkout.informations.validate')
29
+ %button.btn.btn-primary.btn-lg.btn-block{ type: 'submit' }
30
+ = t('stall.checkout.informations.validate')
@@ -1,49 +1,5 @@
1
1
  %h1= t('stall.checkout.payment.title')
2
2
 
3
- %table.table.table-striped
4
- %thead
5
- %tr
6
- %th= LineItem.human_attribute_name(:name)
7
- %th= LineItem.human_attribute_name(:unit_price)
8
- %th= LineItem.human_attribute_name(:quantity)
9
- %th= LineItem.human_attribute_name(:price)
10
- %tbody
11
- - cart.line_items.each do |line_item|
12
- %tr{ data: { :'line-item-id' => line_item.id } }
13
- %td= line_item.name
14
- %td= number_to_currency(line_item.unit_price)
15
- %td= line_item.quantity
16
- %td= number_to_currency(line_item.price)
17
-
18
- - if cart.subtotal != cart.total_price
19
- %tr
20
- %td{ colspan: 3 }= t('stall.carts.recap.subtotal')
21
- %td= number_to_currency(cart.subtotal)
22
-
23
- - if cart.shipment && cart.shipment
24
- %tr
25
- %td{ colspan: 3 }
26
- = t('stall.carts.recap.total_shipment_price')
27
- \:
28
- = cart.shipment.shipping_method.name
29
-
30
- %td= number_to_currency(cart.shipment.price)
31
-
32
- - cart.adjustments.each do |adjustment|
33
- %tr
34
- %td{ colspan: 3 }= adjustment.name
35
- %td= number_to_currency(adjustment.price)
36
-
37
- %tr
38
- %td{ colspan: 3 }= t('stall.carts.recap.total_eot_price')
39
- %td= number_to_currency(cart.total_eot_price)
40
-
41
- %tr
42
- %td{ colspan: 3 }= t('stall.carts.recap.total_vat')
43
- %td= number_to_currency(cart.total_vat)
44
-
45
- %tr
46
- %td{ colspan: 3 }= t('stall.carts.recap.total_price')
47
- %td= number_to_currency(cart.total_price)
3
+ = render partial: 'stall/carts/cart', locals: { cart: cart }
48
4
 
49
5
  = payment_button_for(cart)
@@ -7,4 +7,3 @@
7
7
  .form-actions
8
8
  %button.btn.btn-primary{ type: 'submit' }
9
9
  = t('stall.checkout.shipping_method.validate')
10
-
@@ -0,0 +1,16 @@
1
+ .addresses-fields{ data: { :'addresses-fields' => true } }
2
+ = form.fields_for :address_ownerships, [cart.address_ownership_for(:shipping)] do |ownership_form|
3
+ %fieldset{ data: { :'address-form' => :shipping } }
4
+ = ownership_form.hidden_field :shipping
5
+
6
+ = ownership_form.fields_for :address do |address_form|
7
+ = render partial: 'stall/addresses/nested_fields', locals: { form: address_form }
8
+
9
+ = form.input :use_another_address_for_billing, as: :boolean, input_html: { data: { :'use-another-address-for-billing' => true } }
10
+
11
+ = form.fields_for :address_ownerships, [cart.address_ownership_for(:billing)] do |ownership_form|
12
+ %fieldset{ class: ('hidden' unless params[:use_another_address_for_billing] == '1'), data: { :'address-form' => :billing } }
13
+ = ownership_form.hidden_field :billing
14
+
15
+ = ownership_form.fields_for :address do |address_form|
16
+ = render partial: 'stall/addresses/nested_fields', locals: { form: address_form }
@@ -0,0 +1,14 @@
1
+ .row
2
+ .col-md-2= form.input :civility, collection: Address.civility_enum
3
+ .col-md-5= form.input :first_name
4
+ .col-md-5= form.input :last_name
5
+ .row
6
+ .col-xs-12= form.input :address, input_html: { rows: 1 }
7
+ .row
8
+ .col-xs-12= form.input :address_details, label: false, input_html: { rows: 1 }
9
+ .row
10
+ .col-md-4= form.input :country
11
+ .col-md-4= form.input :zip
12
+ .col-md-4= form.input :city
13
+ .row
14
+ .col-xs-12= form.input :phone
@@ -0,0 +1,45 @@
1
+ %table.table.table-hover
2
+ %thead
3
+ %tr
4
+ %th= LineItem.human_attribute_name(:name)
5
+ %th= LineItem.human_attribute_name(:price)
6
+ %tbody
7
+ - cart.line_items.each do |line_item|
8
+ %tr{ data: { :'line-item-id' => line_item.id } }
9
+ %td
10
+ = line_item.name
11
+ x
12
+ = line_item.quantity
13
+ %td= number_to_currency(line_item.price)
14
+
15
+ %tfoot
16
+ - if cart.subtotal != cart.total_price
17
+ %tr
18
+ %td= t('stall.carts.recap.subtotal')
19
+ %td= number_to_currency(cart.subtotal)
20
+
21
+ - if cart.shipment.try(:persisted?)
22
+ %tr
23
+ %td
24
+ = t('stall.carts.recap.total_shipment_price')
25
+ \:
26
+ = cart.shipment.shipping_method.name
27
+
28
+ %td= number_to_currency(cart.shipment.price)
29
+
30
+ - cart.adjustments.each do |adjustment|
31
+ %tr
32
+ %td= adjustment.name
33
+ %td= number_to_currency(adjustment.price)
34
+
35
+ %tr
36
+ %td= t('stall.carts.recap.total_eot_price')
37
+ %td= number_to_currency(cart.total_eot_price)
38
+
39
+ %tr
40
+ %td= t('stall.carts.recap.total_vat')
41
+ %td= number_to_currency(cart.total_vat)
42
+
43
+ %tr
44
+ %td= t('stall.carts.recap.total_price')
45
+ %td= number_to_currency(cart.total_price)
@@ -11,12 +11,12 @@
11
11
 
12
12
  %tbody
13
13
  = form.fields_for :line_items do |line_item_fields|
14
- %tr{ data: { :'line-item-id' => line_item_fields.object.id } }
14
+ %tr.line-item-row{ data: { :'line-item-id' => line_item_fields.object.id } }
15
15
  %td= line_item_fields.object.name
16
16
  %td= line_item_fields.object.unit_price
17
17
  %td= line_item_fields.input_field :quantity, spinner: false, class: 'form-control', data: { :'quantity-field' => true }
18
18
  %td= line_item_fields.object.price
19
- %td= link_to_remove_association '&times;'.html_safe, line_item_fields
19
+ %td= link_to_remove_association '&times;'.html_safe, line_item_fields, wrapper_class: 'line-item-row'
20
20
 
21
21
  - if @cart.subtotal != @cart.total_price
22
22
  %tr