effective_orders 1.8.1 → 2.0.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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +150 -60
  4. data/Rakefile +0 -3
  5. data/active_admin/effective_orders.rb +14 -9
  6. data/app/assets/javascripts/effective_orders.js +2 -0
  7. data/app/assets/javascripts/effective_orders/{stripe_charges.js.coffee → providers/stripe_charges.js.coffee} +1 -1
  8. data/app/assets/javascripts/effective_orders/{stripe_subscriptions.js.coffee → providers/stripe_subscriptions.js.coffee} +1 -1
  9. data/app/assets/stylesheets/effective_orders/_order.scss +9 -3
  10. data/app/controllers/admin/orders_controller.rb +87 -3
  11. data/app/controllers/concerns/acts_as_active_admin_controller.rb +2 -1
  12. data/app/controllers/effective/carts_controller.rb +4 -2
  13. data/app/controllers/effective/orders_controller.rb +101 -60
  14. data/app/controllers/effective/providers/app_checkout.rb +10 -2
  15. data/app/controllers/effective/providers/ccbill.rb +34 -0
  16. data/app/controllers/effective/providers/cheque.rb +30 -0
  17. data/app/controllers/effective/providers/moneris.rb +7 -7
  18. data/app/controllers/effective/providers/paypal.rb +7 -5
  19. data/app/controllers/effective/providers/pretend.rb +22 -0
  20. data/app/controllers/effective/providers/stripe.rb +26 -24
  21. data/app/controllers/effective/webhooks_controller.rb +1 -1
  22. data/app/helpers/effective_carts_helper.rb +59 -29
  23. data/app/helpers/effective_ccbill_helper.rb +25 -0
  24. data/app/helpers/effective_orders_helper.rb +50 -41
  25. data/app/helpers/effective_paypal_helper.rb +11 -11
  26. data/app/mailers/effective/orders_mailer.rb +95 -20
  27. data/app/models/concerns/acts_as_purchasable.rb +14 -22
  28. data/app/models/effective/cart.rb +9 -15
  29. data/app/models/effective/cart_item.rb +15 -13
  30. data/app/models/effective/customer.rb +9 -9
  31. data/app/models/effective/datatables/order_items.rb +14 -8
  32. data/app/models/effective/datatables/orders.rb +56 -69
  33. data/app/models/effective/order.rb +250 -139
  34. data/app/models/effective/order_item.rb +23 -16
  35. data/app/models/effective/product.rb +23 -0
  36. data/app/models/effective/providers/ccbill_postback.rb +85 -0
  37. data/app/models/effective/{stripe_charge.rb → providers/stripe_charge.rb} +1 -1
  38. data/app/models/effective/subscription.rb +16 -12
  39. data/app/models/effective/tax_rate_calculator.rb +45 -0
  40. data/app/views/admin/customers/index.html.haml +2 -5
  41. data/app/views/admin/order_items/index.html.haml +2 -5
  42. data/app/views/admin/orders/_actions.html.haml +2 -0
  43. data/app/views/admin/orders/_form.html.haml +28 -0
  44. data/app/views/admin/orders/_order_item_fields.html.haml +9 -0
  45. data/app/views/admin/orders/index.html.haml +9 -5
  46. data/app/views/admin/orders/new.html.haml +3 -0
  47. data/app/views/effective/carts/_cart.html.haml +3 -12
  48. data/app/views/effective/carts/_cart_actions.html.haml +4 -0
  49. data/app/views/effective/carts/show.html.haml +10 -12
  50. data/app/views/effective/orders/_checkout_step1.html.haml +46 -0
  51. data/app/views/effective/orders/_checkout_step2.html.haml +33 -0
  52. data/app/views/effective/orders/_order.html.haml +2 -0
  53. data/app/views/effective/orders/_order_actions.html.haml +10 -5
  54. data/app/views/effective/orders/_order_footer.html.haml +1 -0
  55. data/app/views/effective/orders/_order_items.html.haml +11 -9
  56. data/app/views/effective/orders/_order_note.html.haml +8 -0
  57. data/app/views/effective/orders/_order_note_fields.html.haml +5 -0
  58. data/app/views/effective/orders/_order_shipping.html.haml +4 -4
  59. data/app/views/effective/orders/_order_user_fields.html.haml +1 -0
  60. data/app/views/effective/orders/_orders_table.html.haml +27 -0
  61. data/app/views/effective/orders/ccbill/_form.html.haml +24 -0
  62. data/app/views/effective/orders/checkout_step1.html.haml +3 -0
  63. data/app/views/effective/orders/checkout_step2.html.haml +3 -0
  64. data/app/views/effective/orders/cheque/_form.html.haml +2 -0
  65. data/app/views/effective/orders/cheque/pay_by_cheque.html.haml +9 -0
  66. data/app/views/effective/orders/declined.html.haml +4 -2
  67. data/app/views/effective/orders/my_purchases.html.haml +1 -1
  68. data/app/views/effective/orders/my_sales.html.haml +1 -1
  69. data/app/views/effective/orders/purchased.html.haml +3 -2
  70. data/app/views/effective/orders/show.html.haml +1 -1
  71. data/app/views/effective/orders/stripe/_form.html.haml +5 -5
  72. data/app/views/effective/orders_mailer/order_error.html.haml +11 -0
  73. data/app/views/effective/orders_mailer/payment_request_to_buyer.html.haml +13 -0
  74. data/app/views/effective/orders_mailer/pending_order_invoice_to_buyer.html.haml +13 -0
  75. data/app/views/layouts/effective_orders_mailer_layout.html.haml +7 -7
  76. data/config/routes.rb +39 -24
  77. data/db/migrate/01_create_effective_orders.rb.erb +20 -1
  78. data/db/upgrade/03_upgrade_effective_orders_from1x.rb.erb +95 -0
  79. data/lib/effective_orders.rb +67 -9
  80. data/lib/effective_orders/app_checkout_service.rb +1 -2
  81. data/lib/effective_orders/engine.rb +46 -14
  82. data/lib/effective_orders/version.rb +1 -1
  83. data/lib/generators/effective_orders/install_generator.rb +1 -0
  84. data/lib/generators/effective_orders/upgrade_from03x_generator.rb +1 -0
  85. data/lib/generators/effective_orders/upgrade_from1x_generator.rb +31 -0
  86. data/lib/generators/templates/effective_orders.rb +131 -66
  87. data/lib/generators/templates/effective_orders_mailer_preview.rb +28 -13
  88. data/spec/controllers/admin/orders_controller_spec.rb +242 -0
  89. data/spec/controllers/ccbill_orders_controller_spec.rb +103 -0
  90. data/spec/controllers/moneris_orders_controller_spec.rb +23 -23
  91. data/spec/controllers/orders_controller_spec.rb +167 -79
  92. data/spec/controllers/stripe_orders_controller_spec.rb +7 -7
  93. data/spec/dummy/app/models/product.rb +0 -8
  94. data/spec/dummy/app/models/product_with_float_price.rb +0 -8
  95. data/spec/dummy/app/models/user.rb +2 -19
  96. data/spec/dummy/config/application.rb +2 -1
  97. data/spec/dummy/config/environments/test.rb +1 -0
  98. data/spec/dummy/config/initializers/effective_orders.rb +109 -64
  99. data/spec/dummy/db/schema.rb +15 -2
  100. data/spec/dummy/db/test.sqlite3 +0 -0
  101. data/spec/dummy/log/test.log +0 -258
  102. data/spec/models/acts_as_purchasable_spec.rb +8 -6
  103. data/spec/models/factories_spec.rb +7 -1
  104. data/spec/models/order_item_spec.rb +1 -1
  105. data/spec/models/order_spec.rb +165 -46
  106. data/spec/models/stripe_charge_spec.rb +5 -5
  107. data/spec/spec_helper.rb +2 -0
  108. data/spec/support/factories.rb +49 -33
  109. metadata +47 -64
  110. data/app/views/effective/orders/_checkout_step_1.html.haml +0 -43
  111. data/app/views/effective/orders/_checkout_step_2.html.haml +0 -25
  112. data/app/views/effective/orders/_my_purchases.html.haml +0 -17
  113. data/app/views/effective/orders/checkout.html.haml +0 -3
  114. data/app/views/effective/orders/new.html.haml +0 -4
  115. data/spec/dummy/log/development.log +0 -82
@@ -6,24 +6,27 @@ module Effective
6
6
  belongs_to :purchasable, :polymorphic => true
7
7
  belongs_to :seller, :class_name => 'User'
8
8
 
9
- structure do
10
- title :string, :validates => [:presence]
11
- quantity :integer, :validates => [:presence, :numericality]
12
- price :integer, :default => 0, :validates => [:numericality]
13
- tax_exempt :boolean, :validates => [:inclusion => {:in => [true, false]}]
14
- tax_rate :decimal, :precision => 5, :scale => 3, :default => 0.000, :validates => [:presence]
9
+ delegate :purchased_download_url, :to => :purchasable
10
+ delegate :purchased?, :declined?, :to => :order
15
11
 
16
- timestamps
17
- end
12
+ # structure do
13
+ # title :string
14
+ # quantity :integer
15
+ # price :integer, default: 0
16
+ # tax_exempt :boolean
17
+ #
18
+ # timestamps
19
+ # end
18
20
 
19
- validates_associated :purchasable
20
- validates_presence_of :purchasable
21
- accepts_nested_attributes_for :purchasable, :allow_destroy => false, :reject_if => :all_blank, :update_only => true
21
+ validates :purchasable, associated: true, presence: true
22
+ accepts_nested_attributes_for :purchasable, allow_destroy: false, reject_if: :all_blank, update_only: true
22
23
 
23
- validates_presence_of :seller_id, :if => Proc.new { |order_item| EffectiveOrders.stripe_connect_enabled }
24
+ validates :title, presence: true
25
+ validates :quantity, presence: true, numericality: { greater_than: 0 }
26
+ validates :price, numericality: true
27
+ validates :tax_exempt, inclusion: { in: [true, false] }
24
28
 
25
- delegate :purchased_download_url, :to => :purchasable
26
- delegate :purchased?, :declined?, :to => :order
29
+ validates :seller_id, presence: true, if: Proc.new { |order_item| EffectiveOrders.stripe_connect_enabled }
27
30
 
28
31
  scope :sold, -> { joins(:order).where(:orders => {:purchase_state => EffectiveOrders::PURCHASED}) }
29
32
  scope :sold_by, lambda { |user| sold().where(:seller_id => user.try(:id)) }
@@ -36,11 +39,15 @@ module Effective
36
39
  price * quantity
37
40
  end
38
41
 
39
- def tax # This is the total tax, for 3 items if quantity is 3
40
- tax_exempt ? 0 : (subtotal * tax_rate).round(0).to_i
42
+ def tax
43
+ return 0 if tax_exempt?
44
+ raise 'parent Effective::Order must have a tax_rate to compute order item tax' unless order.try(:tax_rate).present?
45
+ (subtotal * order.tax_rate / 100.0).round(0).to_i
41
46
  end
42
47
 
43
48
  def total
49
+ return subtotal if tax_exempt?
50
+ raise 'parent Effective::Order must have a tax_rate to compute order item total' unless order.try(:tax_rate).present?
44
51
  subtotal + tax
45
52
  end
46
53
 
@@ -0,0 +1,23 @@
1
+ module Effective
2
+ class Product < ActiveRecord::Base
3
+ self.table_name = EffectiveOrders.products_table_name.to_s
4
+
5
+ acts_as_purchasable
6
+
7
+ # structure do
8
+ # title :string
9
+ # price :integer, default: 0
10
+ # tax_exempt :boolean, default: false
11
+ #
12
+ # timestamps
13
+ # end
14
+
15
+ validates :title, presence: true
16
+ validates :price, numericality: { greater_than: 0 }
17
+
18
+ def to_s
19
+ self[:title] || 'New Product'
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,85 @@
1
+ # https://www.ccbill.com/cs/wiki/tiki-index.php?page=Background+Post
2
+ class Effective::Providers::CcbillPostback
3
+ attr_reader :params
4
+
5
+ def initialize(params)
6
+ @params = params
7
+ end
8
+
9
+ def verified?
10
+ params[:responseDigest] == digest(digest_value)
11
+ end
12
+
13
+ def matches?(order)
14
+ price == order.total && order_id == order.to_param
15
+ end
16
+
17
+ def approval?
18
+ !denial?
19
+ end
20
+
21
+ def denial?
22
+ # denialId is for subscriptions only
23
+ [:reasonForDeclineCode, :reasonForDecline, :denialId].any? {|key| params[key].present?}
24
+ end
25
+
26
+ def order_details
27
+ @order_details ||= get_order_details
28
+ end
29
+
30
+ def order_id
31
+ params[:order_id]
32
+ end
33
+
34
+ private
35
+
36
+ # https://www.ccbill.com/cs/wiki/tiki-index.php?page=Dynamic+Pricing+User+Guide#Postback
37
+ def digest_value
38
+ if approval?
39
+ "#{params[:subscription_id]}1#{salt}" # the `subscriptionId` param in the linked docs is a typo
40
+ else
41
+ "#{params[:denialId]}0#{salt}"
42
+ end
43
+ end
44
+
45
+ def digest(value)
46
+ Digest::MD5.hexdigest(value)
47
+ end
48
+
49
+ def salt
50
+ EffectiveOrders.ccbill[:dynamic_pricing_salt]
51
+ end
52
+
53
+ # in cents
54
+ def price
55
+ return @price if @price.present?
56
+ formatted_price = params[:initialFormattedPrice] # example: "&#36;10.00"
57
+ formatted_price = Nokogiri::HTML::DocumentFragment.parse(formatted_price).to_s # => "$10.00"
58
+ match = formatted_price.match(/^\D(\d*.\d\d)$/) # {a currency symbol}(digits.two digits)
59
+ return false unless match.present?
60
+ formatted_price = match[1] # => "10.00"
61
+ @price = formatted_price.sub('.', '').to_i # => 1000
62
+ end
63
+
64
+ def get_order_details
65
+ # ignore some params
66
+ keepable = params.except(*ignorable_params)
67
+ # remove blanks
68
+ keepable.inject({}) do |details, kv_pair|
69
+ details[kv_pair[0]] = kv_pair[1] if kv_pair[1].present?
70
+ details
71
+ end
72
+ end
73
+
74
+ def ignorable_params
75
+ [
76
+ # we have these already
77
+ :clientAccnum,
78
+ :clientSubacc,
79
+ :productDesc,
80
+ # a hash of billing information which CCBill doesn't share the format of (afaik)
81
+ :paymentAccount
82
+ ]
83
+ end
84
+ end
85
+
@@ -1,5 +1,5 @@
1
1
  # This is an object for the stripe charge form
2
- module Effective
2
+ module Effective::Providers
3
3
  class StripeCharge
4
4
  extend ActiveModel::Naming
5
5
  include ActiveModel::Conversion
@@ -8,21 +8,25 @@ module Effective
8
8
 
9
9
  belongs_to :customer
10
10
 
11
- structure do
12
- stripe_plan_id :string, :validates => [:presence] # This will be 'Weekly' or something like that
13
- stripe_subscription_id :string
14
- stripe_coupon_id :string
15
-
16
- title :string, :validates => [:presence]
17
- price :integer, :default => 0, :validates => [:numericality => {:greater_than => 0}]
18
-
19
- timestamps
20
- end
11
+ # structure do
12
+ # stripe_plan_id :string # This will be 'Weekly' or something like that
13
+ # stripe_subscription_id :string
14
+ # stripe_coupon_id :string
15
+ #
16
+ # title :string
17
+ # price :integer, default: 0
18
+ #
19
+ # timestamps
20
+ # end
21
21
 
22
22
  delegate :user, :user_id, :to => :customer
23
23
 
24
- validates_presence_of :customer
25
- validates_uniqueness_of :customer_id, :scope => [:stripe_plan_id] # Can only be on each plan once.
24
+ validates :stripe_plan_id, presence: true
25
+ validates :title, presence: true
26
+ validates :price, numericality: { greater_than: 0 }
27
+
28
+ validates :customer, presence: true
29
+ validates :customer_id, uniqueness: { scope: [:stripe_plan_id] } # Can only be on each plan once.
26
30
 
27
31
  before_validation do
28
32
  self.errors.add(:stripe_plan_id, "is an invalid Plan") if stripe_plan_id.present? && stripe_plan.blank?
@@ -0,0 +1,45 @@
1
+ module Effective
2
+ class TaxRateCalculator
3
+ attr_reader :order
4
+
5
+ RATES = {
6
+ 'CA' => { # Canada
7
+ 'AB' => 5.00, # Alberta
8
+ 'BC' => 5.00, # British Columbia
9
+ 'MB' => 5.00, # Manitoba
10
+ 'NB' => 13.0, # New Brunswick
11
+ 'NL' => 13.0, # Newfoundland and Labrador
12
+ 'NT' => 5.00, # Northwest Territories
13
+ 'NS' => 15.0, # Nova Scotia
14
+ 'ON' => 13.0, # Ontario
15
+ 'PE' => 14.0, # Prince Edward Island
16
+ 'QC' => 5.00, # Quebec
17
+ 'SK' => 5.00, # Saskatchewan
18
+ 'YT' => 5.00, # Yukon Territory
19
+ 'NU' => 5.00 # Nunavut
20
+ }
21
+ }
22
+
23
+ def initialize(order:)
24
+ @order = order
25
+ end
26
+
27
+ def tax_rate
28
+ return nil unless order.billing_address.try(:country_code).present?
29
+
30
+ country = order.billing_address.country_code
31
+ state = order.billing_address.state_code
32
+
33
+ rate = RATES[country]
34
+ return rate if rate.kind_of?(Numeric)
35
+ return unknown_tax_rate() if rate.nil?
36
+
37
+ rate[state].presence || unknown_tax_rate()
38
+ end
39
+
40
+ def unknown_tax_rate
41
+ order.skip_buyer_validations? ? nil : 0
42
+ end
43
+
44
+ end
45
+ end
@@ -1,12 +1,9 @@
1
- %h2.effective-orders-page-title Customers
1
+ %h2.effective-orders-page-title= (@page_title || 'Customers')
2
2
 
3
3
  %p.text-right= link_to 'Stripe Dashboard: Customers', 'https://manage.stripe.com/customers', :class => 'btn btn-primary'
4
4
 
5
5
  - if @datatable.nil?
6
- %p
7
- Please install
8
- = link_to 'effective_datatables', 'https://github.com/code-and-effect/effective_datatables'
9
- to see this page.
6
+ %p Please install #{link_to 'effective_datatables', 'https://github.com/code-and-effect/effective_datatables'} to see this page.
10
7
  - elsif @datatable.present?
11
8
  = render_datatable @datatable
12
9
  - else
@@ -1,10 +1,7 @@
1
- %h2.effective-orders-page-title Order Items
1
+ %h2.effective-orders-page-title= (@page_title || 'Order Items')
2
2
 
3
3
  - if @datatable.nil?
4
- %p
5
- Please install
6
- = link_to 'effective_datatables', 'https://github.com/code-and-effect/effective_datatables'
7
- to see this page.
4
+ %p Please install #{link_to 'effective_datatables', 'https://github.com/code-and-effect/effective_datatables'} to see this page.
8
5
  - elsif @datatable.present?
9
6
  = render_datatable @datatable
10
7
  - else
@@ -0,0 +1,2 @@
1
+ = link_to (datatables_admin_path? ? effective_orders.admin_order_path(order) : effective_orders.order_path(order)), title: 'View' do
2
+ %span.glyphicon.glyphicon-eye-open
@@ -0,0 +1,28 @@
1
+ - unless defined?(Cocoon)
2
+ Please install #{link_to 'cocoon', 'https://github.com/nathanvda/cocoon'} to see this page.
3
+ - else
4
+ = simple_form_for [:admin, order], (EffectiveOrders.admin_simple_form_options || {}).merge(url: effective_orders.admin_orders_path) do |f|
5
+ = f.association :user,
6
+ label: 'Buyer',
7
+ required: true,
8
+ as: (defined?(EffectiveFormInputs) ? :effective_select : :select),
9
+ collection: @users || User.all.to_a.sort { |user1, user2| user1.to_s <=> user2.to_s }
10
+
11
+ %h3 Order Items
12
+ .order_items
13
+ - f.object.order_items.build unless f.object.order_items.present?
14
+ = f.simple_fields_for :order_items do |order_item|
15
+ = render 'order_item_fields', f: order_item
16
+
17
+ .links
18
+ = link_to_add_association '+ Add line item', f, :order_items, partial: 'order_item_fields'
19
+
20
+ = f.input :send_payment_request_to_buyer,
21
+ as: :boolean,
22
+ label: 'Yes, send a payment request email to the buyer.',
23
+ value: (f.object.send_payment_request_to_buyer.nil? ? EffectiveOrders.mailer[:send_payment_request_to_buyer] : f.object.send_payment_request_to_buyer?)
24
+
25
+ .form-group.pull-right
26
+ = f.button :submit, 'Save', data: { disable_with: 'Saving...' }
27
+ = f.button :submit, 'Save and Add New', data: { disable_with: 'Saving...' }
28
+ = link_to 'Cancel', effective_orders.admin_orders_path
@@ -0,0 +1,9 @@
1
+ .nested-fields.order-item
2
+ .row
3
+ - f.object.purchasable ||= Effective::Product.new
4
+ = f.simple_fields_for :purchasable do |purchasable|
5
+ .col-sm-2= f.input :quantity, input_html: { value: f.object.quantity || 1, min: 1 }
6
+ .col-sm-4= purchasable.input :title, input_html: { maxlength: 255 }
7
+ .col-sm-2= purchasable.input :price, as: (defined?(EffectiveFormInputs) ? :effective_price : :price)
8
+ .col-sm-2= purchasable.input :tax_exempt, label: 'Tax Exempt', input_html: { title: 'When checked, tax will not be applied to this item' }
9
+ .col-sm-2.remove-nested-fields= link_to_remove_association('Remove line item', f)
@@ -1,11 +1,15 @@
1
- %h2.effective-orders-page-title Orders
1
+ %h2.effective-orders-page-title= (@page_title || 'Orders')
2
+
3
+ %p.text-right.effective-orders-page-action= link_to 'New Order', effective_orders.new_admin_order_path, :class => 'btn btn-primary'
2
4
 
3
5
  - if @datatable.nil?
4
- %p
5
- Please install
6
- = link_to 'effective_datatables', 'https://github.com/code-and-effect/effective_datatables'
7
- to see this page.
6
+ %p Please install #{link_to 'effective_datatables', 'https://github.com/code-and-effect/effective_datatables'} to see this page.
8
7
  - elsif @datatable.present?
9
8
  = render_datatable @datatable
10
9
  - else
11
10
  %p There are no orders present
11
+
12
+ - if @datatable.present?
13
+ %p.text-right= link_to 'New Order', effective_orders.new_admin_order_path, :class => 'btn btn-primary'
14
+
15
+
@@ -0,0 +1,3 @@
1
+ %h2.effective-orders-page-title= (@page_title || 'New Order')
2
+
3
+ = render partial: 'form', locals: { order: @order }
@@ -19,19 +19,10 @@
19
19
  - if cart.empty?
20
20
  %tr
21
21
  %td.quantity
22
- %td.item There are no items in your shopping cart
22
+ %td.item Your cart is empty.
23
23
  %td.price
24
24
  %tfoot
25
- - if cart.tax > 0
26
- %tr
27
- %th.quantity
28
- %th.subtotal Subtotal
29
- %td.price.subtotal-price= price_to_currency(cart.subtotal)
30
- %tr
31
- %th.quantity
32
- %th.tax Tax
33
- %td.price.tax-price= price_to_currency(cart.tax)
34
25
  %tr
35
26
  %th.quantity
36
- %th.total Total Due
37
- %td.price.total-price= price_to_currency(cart.total)
27
+ %th.subtotal Subtotal
28
+ %td.price.subtotal-price= price_to_currency(cart.subtotal)
@@ -0,0 +1,4 @@
1
+ .effective-order-actions.pull-right
2
+ %p
3
+ = link_to_checkout
4
+ = link_to_empty_cart
@@ -1,20 +1,18 @@
1
- %h2.effective-orders-page-title Shopping Cart
1
+ %h2.effective-orders-page-title= (@page_title || 'My Cart')
2
2
 
3
3
  - if @cart.empty?
4
4
  %p Your cart is empty.
5
-
6
- %hr
7
- = link_to 'Home', root_url, :class => 'btn btn-primary'
8
- - if EffectiveOrders.show_order_history_button
9
- = link_to 'Order History', effective_orders.my_purchases_path, class: 'btn btn-default'
10
-
11
5
  - else
12
6
  %p Your cart has #{@cart.cart_items.length} items.
13
7
 
14
8
  = render_cart(@cart)
15
-
16
9
  %hr
17
- = link_to_checkout :class => 'btn btn-primary pull-right'
18
- = link_to_empty_cart
19
- - if EffectiveOrders.show_order_history_button
20
- = link_to 'Order History', effective_orders.my_purchases_path, class: 'btn btn-default', rel: :nofollow
10
+ = render partial: '/effective/carts/cart_actions', locals: { cart: @cart }
11
+
12
+ - if @pending_orders.present?
13
+ %h3 Pending Orders
14
+ %p The following orders are ready for you to purchase:
15
+ = render_orders_table(@pending_orders)
16
+
17
+ - if EffectiveOrders.show_order_history_button
18
+ = link_to_my_purchases(label: 'Order History')
@@ -0,0 +1,46 @@
1
+ .effective-order
2
+ = simple_form_for(order, (EffectiveOrders.simple_form_options || {}).merge(url: (order.new_record? ? effective_orders.orders_path : effective_orders.order_path(order)))) do |f|
3
+ = render partial: 'effective/orders/order_items', locals: {order: order, form: f}
4
+
5
+ - if order.errors[:order_items].present?
6
+ %p.inline-errors= order.errors[:order_items].first
7
+
8
+ - if order.errors[:total].present?
9
+ %p.inline-errors= order.errors[:total].first.gsub(EffectiveOrders.minimum_charge.to_i.to_s, price_to_currency(EffectiveOrders.minimum_charge.to_i))
10
+
11
+ - if EffectiveOrders.collect_user_fields.present? && (f.object.user rescue nil).present?
12
+ = render partial: 'effective/orders/order_user_fields', locals: {form: f, user: f.object.user }
13
+
14
+ - num_addresses = [EffectiveOrders.require_billing_address, EffectiveOrders.require_shipping_address].count(true)
15
+
16
+ - if num_addresses > 0
17
+ .row
18
+ - if EffectiveOrders.require_billing_address
19
+ %div{class: "col-sm-#{12 / num_addresses}"}
20
+ %h3 Billing Address
21
+ = effective_address_fields(f, :billing_address)
22
+ - if f.object.user.respond_to?(:billing_address=)
23
+ = f.input :save_billing_address, as: :boolean, label: 'Save as my default billing address', required: false
24
+
25
+ - if EffectiveOrders.require_shipping_address
26
+ %div{class: "col-sm-#{12 / num_addresses}"}
27
+ %h3 Shipping Address
28
+ - if EffectiveOrders.require_billing_address && EffectiveOrders.require_shipping_address
29
+ .shipping_address_fields{style: (f.object.shipping_address_same_as_billing? && (f.object.errors[:shipping_address] || []).blank?) ? 'display: none;' : 'display: block;'}
30
+ = effective_address_fields(f, :shipping_address)
31
+ - if f.object.user.respond_to?(:shipping_address=)
32
+ = f.input :save_shipping_address, as: :boolean, label: 'Save as my default shipping address', required: false
33
+
34
+ = f.input :shipping_address_same_as_billing, as: :boolean, label: 'My shipping address is the same as my billing address', required: false
35
+
36
+ - if EffectiveOrders.collect_note
37
+ = render partial: 'effective/orders/order_note_fields', locals: {form: f}
38
+
39
+ - unless f.object.pending? || current_cart.try(:empty?)
40
+ = link_to_current_cart(label: 'Change Items')
41
+
42
+ .pull-right
43
+ - if order.total == 0 && EffectiveOrders.allow_free_orders
44
+ = f.submit order_checkout_label(:free), class: 'btn btn-primary', rel: :nofollow, data: {'disable_with' => 'Processing...' }
45
+ - else
46
+ = f.submit 'Save and Continue', class: 'btn btn-primary', rel: :nofollow, data: {'disable_with' => 'Saving...' }