effective_orders 2.2.4 → 3.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.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +124 -84
- data/app/assets/javascripts/effective_orders/customers.js.coffee +39 -0
- data/app/assets/javascripts/effective_orders/providers/{stripe_charges.js.coffee → stripe.js.coffee} +15 -13
- data/app/assets/javascripts/effective_orders/subscriptions.js.coffee +73 -0
- data/app/assets/stylesheets/effective_orders.scss +2 -1
- data/app/assets/stylesheets/effective_orders/_order.scss +16 -8
- data/app/assets/stylesheets/effective_orders/_subscriptions.scss +14 -0
- data/app/controllers/admin/customers_controller.rb +11 -8
- data/app/controllers/admin/order_items_controller.rb +4 -8
- data/app/controllers/admin/orders_controller.rb +133 -87
- data/app/controllers/effective/carts_controller.rb +18 -8
- data/app/controllers/effective/concerns/purchase.rb +39 -0
- data/app/controllers/effective/customers_controller.rb +43 -0
- data/app/controllers/effective/orders_controller.rb +73 -119
- data/app/controllers/effective/providers/app_checkout.rb +3 -1
- data/app/controllers/effective/providers/ccbill.rb +4 -6
- data/app/controllers/effective/providers/cheque.rb +20 -11
- data/app/controllers/effective/providers/free.rb +33 -0
- data/app/controllers/effective/providers/mark_as_paid.rb +33 -0
- data/app/controllers/effective/providers/moneris.rb +9 -17
- data/app/controllers/effective/providers/paypal.rb +4 -6
- data/app/controllers/effective/providers/pretend.rb +4 -4
- data/app/controllers/effective/providers/refund.rb +39 -0
- data/app/controllers/effective/providers/stripe.rb +19 -40
- data/app/controllers/effective/providers/stripe_connect.rb +2 -6
- data/app/controllers/effective/webhooks_controller.rb +44 -95
- data/app/datatables/effective_customers_datatable.rb +21 -29
- data/app/datatables/effective_order_items_datatable.rb +77 -79
- data/app/datatables/effective_orders_datatable.rb +67 -57
- data/app/helpers/effective_carts_helper.rb +17 -14
- data/app/helpers/effective_orders_helper.rb +40 -56
- data/app/helpers/effective_paypal_helper.rb +3 -3
- data/app/helpers/effective_stripe_helper.rb +47 -18
- data/app/helpers/effective_subscriptions_helper.rb +79 -0
- data/app/mailers/effective/orders_mailer.rb +125 -2
- data/app/models/concerns/acts_as_purchasable.rb +23 -33
- data/app/models/concerns/acts_as_subscribable.rb +68 -0
- data/app/models/concerns/acts_as_subscribable_buyer.rb +22 -0
- data/app/models/effective/cart.rb +53 -24
- data/app/models/effective/cart_item.rb +6 -12
- data/app/models/effective/customer.rb +51 -54
- data/app/models/effective/order.rb +160 -147
- data/app/models/effective/order_item.rb +18 -21
- data/app/models/effective/product.rb +7 -7
- data/app/models/effective/providers/ccbill_postback.rb +1 -1
- data/app/models/effective/providers/stripe_charge.rb +8 -19
- data/app/models/effective/subscripter.rb +230 -0
- data/app/models/effective/subscription.rb +27 -76
- data/app/models/effective/tax_rate_calculator.rb +10 -7
- data/app/views/admin/customers/_actions.html.haml +1 -2
- data/app/views/admin/customers/index.html.haml +1 -1
- data/app/views/admin/customers/show.html.haml +6 -0
- data/app/views/admin/orders/_actions.html.haml +9 -7
- data/app/views/admin/orders/_form.html.haml +11 -7
- data/app/views/admin/orders/_order_actions.html.haml +2 -1
- data/app/views/admin/orders/_order_item_fields.html.haml +1 -1
- data/app/views/admin/orders/edit.html.haml +4 -0
- data/app/views/admin/orders/index.html.haml +1 -4
- data/app/views/admin/orders/new.html.haml +1 -1
- data/app/views/admin/orders/show.html.haml +5 -6
- data/app/views/effective/carts/_cart.html.haml +2 -2
- data/app/views/effective/carts/show.html.haml +2 -2
- data/app/views/effective/customers/_customer.html.haml +152 -0
- data/app/views/effective/customers/_fields.html.haml +12 -0
- data/app/views/effective/customers/_form.html.haml +13 -0
- data/app/views/effective/customers/edit.html.haml +3 -0
- data/app/views/effective/orders/_checkout_step1.html.haml +8 -15
- data/app/views/effective/orders/_checkout_step2.html.haml +34 -21
- data/app/views/effective/orders/_order.html.haml +8 -9
- data/app/views/effective/orders/_order_actions.html.haml +7 -8
- data/app/views/effective/orders/_order_header.html.haml +1 -1
- data/app/views/effective/orders/_order_items.html.haml +11 -5
- data/app/views/effective/orders/_order_note.html.haml +4 -7
- data/app/views/effective/orders/_orders_table.html.haml +26 -26
- data/app/views/effective/orders/app_checkout/_form.html.haml +2 -2
- data/app/views/effective/orders/ccbill/_form.html.haml +1 -1
- data/app/views/effective/orders/cheque/_form.html.haml +3 -1
- data/app/views/effective/orders/declined.html.haml +1 -1
- data/app/views/effective/orders/{checkout_step1.html.haml → edit.html.haml} +0 -0
- data/app/views/effective/orders/free/_form.html.haml +4 -0
- data/app/views/effective/orders/index.html.haml +2 -4
- data/app/views/effective/orders/mark_as_paid/_form.html.haml +32 -0
- data/app/views/effective/orders/moneris/_form.html.haml +6 -6
- data/app/views/effective/orders/{checkout_step2.html.haml → new.html.haml} +1 -1
- data/app/views/effective/orders/paypal/_form.html.haml +2 -2
- data/app/views/effective/orders/pretend/_form.html.haml +2 -2
- data/app/views/effective/orders/purchased.html.haml +3 -0
- data/app/views/effective/orders/refund/_form.html.haml +32 -0
- data/app/views/effective/orders/show.html.haml +4 -1
- data/app/views/effective/orders/stripe/_form.html.haml +5 -5
- data/app/views/effective/orders_mailer/subscription_canceled.html.haml +9 -0
- data/app/views/effective/orders_mailer/subscription_payment_failed.html.haml +9 -0
- data/app/views/effective/orders_mailer/subscription_payment_succeeded.html.haml +9 -0
- data/app/views/effective/orders_mailer/subscription_trial_expired.html.haml +5 -0
- data/app/views/effective/orders_mailer/subscription_trial_expiring.html.haml +7 -0
- data/app/views/effective/subscriptions/_fields.html.haml +16 -0
- data/app/views/effective/subscriptions/_plan.html.haml +21 -0
- data/app/views/layouts/effective_orders_mailer_layout.html.haml +6 -8
- data/config/effective_orders.rb +41 -20
- data/config/routes.rb +48 -48
- data/db/migrate/01_create_effective_orders.rb.erb +19 -5
- data/lib/effective_orders.rb +78 -42
- data/lib/effective_orders/engine.rb +36 -82
- data/lib/effective_orders/version.rb +1 -1
- data/lib/generators/effective_orders/install_generator.rb +2 -2
- data/lib/generators/templates/effective_orders_mailer_preview.rb +39 -4
- data/lib/tasks/effective_orders_tasks.rake +42 -0
- data/spec/controllers/carts_controller_spec.rb +1 -1
- data/spec/controllers/moneris_orders_controller_spec.rb +4 -4
- data/spec/controllers/orders_controller_spec.rb +4 -4
- data/spec/controllers/stripe_orders_controller_spec.rb +2 -2
- data/spec/controllers/webhooks_controller_spec.rb +1 -1
- data/spec/dummy/config/initializers/effective_orders.rb +1 -7
- data/spec/dummy/db/schema.rb +1 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +3 -0
- data/spec/models/acts_as_purchasable_spec.rb +0 -56
- data/spec/models/customer_spec.rb +3 -3
- data/spec/models/order_spec.rb +2 -2
- data/spec/spec_helper.rb +1 -1
- data/spec/support/factories.rb +2 -1
- metadata +37 -49
- data/active_admin/effective_carts.rb +0 -14
- data/active_admin/effective_orders.rb +0 -112
- data/app/assets/javascripts/effective_orders/providers/stripe_subscriptions.js.coffee +0 -28
- data/app/controllers/concerns/acts_as_active_admin_controller.rb +0 -69
- data/app/controllers/effective/subscriptions_controller.rb +0 -126
- data/app/models/effective/datatables/customers.rb +0 -40
- data/app/models/effective/datatables/order_items.rb +0 -101
- data/app/models/effective/datatables/orders.rb +0 -91
- data/app/models/inputs/price_field.rb +0 -63
- data/app/models/inputs/price_form_input.rb +0 -7
- data/app/models/inputs/price_formtastic_input.rb +0 -9
- data/app/models/inputs/price_input.rb +0 -19
- data/app/models/inputs/price_simple_form_input.rb +0 -8
- data/app/views/admin/orders/_form_mark_as_paid.html.haml +0 -33
- data/app/views/admin/orders/_order_payment_details.html.haml +0 -5
- data/app/views/admin/orders/mark_as_paid.html.haml +0 -7
- data/app/views/effective/orders/stripe/_subscription_fields.html.haml +0 -7
- data/app/views/effective/subscriptions/index.html.haml +0 -22
- data/app/views/effective/subscriptions/new.html.haml +0 -9
- data/app/views/effective/subscriptions/show.html.haml +0 -49
- data/db/upgrade/02_upgrade_effective_orders_from03x.rb.erb +0 -29
- data/db/upgrade/03_upgrade_effective_orders_from1x.rb.erb +0 -98
- data/db/upgrade/upgrade_price_column_on_table.rb.erb +0 -17
- data/lib/generators/effective_orders/upgrade_from03x_generator.rb +0 -31
- data/lib/generators/effective_orders/upgrade_from1x_generator.rb +0 -27
- data/lib/generators/effective_orders/upgrade_price_column_generator.rb +0 -30
@@ -7,90 +7,88 @@ module Effective
|
|
7
7
|
end
|
8
8
|
|
9
9
|
acts_as_addressable(
|
10
|
-
:
|
11
|
-
:
|
10
|
+
billing: { singular: true, use_full_name: EffectiveOrders.use_address_full_name },
|
11
|
+
shipping: { singular: true, use_full_name: EffectiveOrders.use_address_full_name }
|
12
12
|
)
|
13
13
|
|
14
|
-
attr_accessor :save_billing_address, :save_shipping_address # save these addresses to the user if selected
|
15
14
|
attr_accessor :terms_and_conditions # Yes, I agree to the terms and conditions
|
16
15
|
|
17
16
|
# Settings in the /admin action forms
|
18
|
-
attr_accessor :send_payment_request_to_buyer #
|
19
|
-
attr_accessor :send_mark_as_paid_email_to_buyer #
|
20
|
-
attr_accessor :skip_buyer_validations #
|
17
|
+
attr_accessor :send_payment_request_to_buyer # Set by Admin::Orders#new. Should the payment request email be sent after creating an order?
|
18
|
+
attr_accessor :send_mark_as_paid_email_to_buyer # Set by Admin::Orders#mark_as_paid
|
19
|
+
attr_accessor :skip_buyer_validations # Set by Admin::Orders#create
|
20
|
+
attr_accessor :skip_minimum_charge_validation # Set by Admin::Orders#show
|
21
21
|
|
22
|
-
belongs_to :user, validate: false # This is the user
|
23
|
-
has_many :order_items, inverse_of: :order
|
22
|
+
belongs_to :user, validate: false # This is the buyer/user of the order. We validate it below.
|
23
|
+
has_many :order_items, -> { order(:id) }, inverse_of: :order, class_name: 'Effective::OrderItem'
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
accepts_nested_attributes_for :order_items, allow_destroy: false, reject_if: :all_blank
|
26
|
+
accepts_nested_attributes_for :user, allow_destroy: false, update_only: true
|
27
|
+
|
28
|
+
# Attributes
|
29
|
+
# purchase_state :string
|
30
|
+
# purchased_at :datetime
|
28
31
|
#
|
29
|
-
#
|
32
|
+
# note_to_buyer :text
|
33
|
+
# note_internal :text
|
30
34
|
#
|
31
|
-
#
|
35
|
+
# payment :text # serialized hash containing all the payment details. see below.
|
32
36
|
#
|
33
|
-
#
|
34
|
-
#
|
37
|
+
# payment_provider :string
|
38
|
+
# payment_card :string
|
35
39
|
#
|
36
|
-
#
|
40
|
+
# tax_rate :decimal, precision: 6, scale: 3
|
37
41
|
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
42
|
+
# subtotal :integer
|
43
|
+
# tax :integer
|
44
|
+
# total :integer
|
41
45
|
#
|
42
|
-
#
|
43
|
-
# end
|
46
|
+
# timestamps
|
44
47
|
|
45
|
-
|
46
|
-
accepts_nested_attributes_for :user, allow_destroy: false, update_only: true
|
48
|
+
serialize :payment, Hash
|
47
49
|
|
48
50
|
before_validation { assign_totals! }
|
49
|
-
before_save { assign_totals! unless self[:total].present? } # Incase we save!(validate: false)
|
50
|
-
|
51
|
-
unless EffectiveOrders.skip_user_validation
|
52
|
-
validates :user_id, presence: true, unless: Proc.new { |order| order.skip_buyer_validations? }
|
53
|
-
validates :user, associated: true, unless: Proc.new { |order| order.skip_buyer_validations? }
|
54
|
-
end
|
55
|
-
|
56
|
-
if EffectiveOrders.collect_note_required
|
57
|
-
validates :note, presence: true, unless: Proc.new { |order| order.skip_buyer_validations? }
|
58
|
-
end
|
59
51
|
|
60
|
-
|
61
|
-
validates :
|
52
|
+
# Order validations
|
53
|
+
validates :order_items, presence: { message: 'No items are present. Please add additional items.' }
|
54
|
+
validates :purchase_state, inclusion: { in: EffectiveOrders::PURCHASE_STATES.keys }
|
55
|
+
validates :subtotal, presence: true
|
62
56
|
|
63
|
-
if EffectiveOrders.
|
64
|
-
validates :
|
57
|
+
if EffectiveOrders.minimum_charge.to_i > 0
|
58
|
+
validates :total, presence: true, numericality: {
|
59
|
+
greater_than_or_equal_to: EffectiveOrders.minimum_charge.to_i,
|
60
|
+
message: "must be $#{'%0.2f' % (EffectiveOrders.minimum_charge.to_i / 100.0)} or more. Please add additional items."
|
61
|
+
}, unless: -> {
|
62
|
+
(total == 0 && EffectiveOrders.allow_free_orders) ||
|
63
|
+
(total < 0 && EffectiveOrders.allow_refunds && skip_minimum_charge_validation?)
|
64
|
+
}
|
65
65
|
end
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
|
67
|
+
# User validations -- An admin skips these when working in the admin/ namespace
|
68
|
+
with_options unless: -> { skip_buyer_validations? } do |order|
|
69
|
+
order.validates :tax_rate, presence: { message: "can't be determined based on billing address" }
|
70
|
+
order.validates :tax, presence: true
|
70
71
|
|
71
|
-
|
72
|
-
|
73
|
-
validates :
|
74
|
-
greater_than_or_equal_to: minimum_charge,
|
75
|
-
message: "A minimum order of #{EffectiveOrders.minimum_charge} is required. Please add additional items to your cart."
|
76
|
-
}, unless: Proc.new { |order| order.total == 0 }
|
77
|
-
else
|
78
|
-
validates :total, numericality: {
|
79
|
-
greater_than_or_equal_to: minimum_charge,
|
80
|
-
message: "A minimum order of #{EffectiveOrders.minimum_charge} is required. Please add additional items to your cart."
|
81
|
-
}
|
72
|
+
unless EffectiveOrders.skip_user_validation
|
73
|
+
order.validates :user_id, presence: true
|
74
|
+
order.validates :user, associated: true
|
82
75
|
end
|
83
|
-
end
|
84
76
|
|
85
|
-
|
77
|
+
if EffectiveOrders.require_billing_address
|
78
|
+
order.validates :billing_address, presence: true
|
79
|
+
end
|
86
80
|
|
87
|
-
|
88
|
-
|
81
|
+
if EffectiveOrders.require_shipping_address
|
82
|
+
order.validates :shipping_address, presence: true
|
83
|
+
end
|
89
84
|
|
90
|
-
|
91
|
-
|
85
|
+
if EffectiveOrders.collect_note_required
|
86
|
+
order.validates :note, presence: true
|
87
|
+
end
|
88
|
+
end
|
92
89
|
|
93
|
-
|
90
|
+
# When Purchased
|
91
|
+
with_options if: -> { purchased? } do |order|
|
94
92
|
order.validates :purchased_at, presence: true
|
95
93
|
order.validates :payment, presence: true
|
96
94
|
|
@@ -98,14 +96,17 @@ module Effective
|
|
98
96
|
order.validates :payment_card, presence: true
|
99
97
|
end
|
100
98
|
|
101
|
-
|
99
|
+
before_save { assign_totals! unless self[:total].present? } # Incase we save!(validate: false)
|
100
|
+
before_save :save_addresses
|
102
101
|
|
103
|
-
|
102
|
+
scope :deep, -> { includes(:user).includes(order_items: :purchasable) }
|
103
|
+
scope :sorted, -> { order(created_at: :desc) }
|
104
104
|
|
105
|
-
scope :purchased, -> { where(purchase_state: EffectiveOrders::PURCHASED) }
|
105
|
+
scope :purchased, -> { sorted.where(purchase_state: EffectiveOrders::PURCHASED) }
|
106
106
|
scope :purchased_by, lambda { |user| purchased.where(user_id: user.try(:id)) }
|
107
107
|
scope :declined, -> { where(purchase_state: EffectiveOrders::DECLINED) }
|
108
108
|
scope :pending, -> { where(purchase_state: EffectiveOrders::PENDING) }
|
109
|
+
|
109
110
|
scope :for_users, -> (users) { # Expects a Users relation, an Array of ids, or Array of users
|
110
111
|
users = users.kind_of?(::ActiveRecord::Relation) ? users.pluck(:id) : Array(users)
|
111
112
|
where(user_id: (users.first.kind_of?(Integer) ? users : users.map { |user| user.id }))
|
@@ -123,21 +124,12 @@ module Effective
|
|
123
124
|
def initialize(*items, user: nil, billing_address: nil, shipping_address: nil)
|
124
125
|
super() # Call super with no arguments
|
125
126
|
|
126
|
-
#
|
127
|
-
self.save_billing_address = true
|
128
|
-
self.save_shipping_address = true
|
129
|
-
|
127
|
+
# Assign user
|
130
128
|
self.user = user || (items.first.user if items.first.kind_of?(Effective::Cart))
|
131
129
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
end
|
136
|
-
|
137
|
-
if shipping_address
|
138
|
-
self.shipping_address = shipping_address
|
139
|
-
self.shipping_address.full_name ||= billing_name
|
140
|
-
end
|
130
|
+
# Assign addresses
|
131
|
+
self.billing_address = billing_address if billing_address
|
132
|
+
self.shipping_address = shipping_address if shipping_address
|
141
133
|
|
142
134
|
add(items) if items.present?
|
143
135
|
end
|
@@ -152,11 +144,20 @@ module Effective
|
|
152
144
|
if item.kind_of?(Effective::Cart)
|
153
145
|
item.cart_items.to_a
|
154
146
|
elsif item.kind_of?(ActsAsPurchasable)
|
155
|
-
Effective::CartItem.new(quantity: quantity
|
147
|
+
Effective::CartItem.new(quantity: quantity, purchasable: item)
|
148
|
+
elsif item.kind_of?(Effective::Order)
|
149
|
+
# Duplicate an existing order
|
150
|
+
self.note_to_buyer ||= item.note_to_buyer
|
151
|
+
self.note_internal ||= item.note_internal
|
152
|
+
|
153
|
+
item.order_items.select { |oi| oi.purchasable.kind_of?(Effective::Product) }.map do |oi|
|
154
|
+
product = Effective::Product.new(title: oi.purchasable.title, price: oi.purchasable.price, tax_exempt: oi.purchasable.tax_exempt)
|
155
|
+
Effective::CartItem.new(quantity: oi.quantity, purchasable: product)
|
156
|
+
end
|
156
157
|
else
|
157
|
-
raise
|
158
|
+
raise 'add() expects one or more acts_as_purchasable objects, or an Effective::Cart'
|
158
159
|
end
|
159
|
-
end
|
160
|
+
end.compact
|
160
161
|
|
161
162
|
# Make sure to reset stored aggregates
|
162
163
|
self.total = nil
|
@@ -175,13 +176,12 @@ module Effective
|
|
175
176
|
|
176
177
|
retval.size == 1 ? retval.first : retval
|
177
178
|
end
|
178
|
-
alias_method :add_to_order, :add
|
179
179
|
|
180
180
|
def user=(user)
|
181
|
-
return if user.nil?
|
182
|
-
|
183
181
|
super
|
184
182
|
|
183
|
+
return unless user.present?
|
184
|
+
|
185
185
|
# Copy user addresses into this order if they are present
|
186
186
|
if user.respond_to?(:billing_address) && user.billing_address.present?
|
187
187
|
self.billing_address = user.billing_address
|
@@ -191,64 +191,47 @@ module Effective
|
|
191
191
|
self.shipping_address = user.shipping_address
|
192
192
|
end
|
193
193
|
|
194
|
-
|
195
|
-
if EffectiveOrders.require_billing_address
|
196
|
-
self.billing_address ||= Effective::Address.new()
|
197
|
-
end
|
198
|
-
|
199
|
-
if EffectiveOrders.require_shipping_address
|
200
|
-
self.shipping_address ||= Effective::Address.new()
|
201
|
-
end
|
202
|
-
|
203
|
-
# Ensure the Full Name is assigned when an address exists
|
204
|
-
if billing_address.present? && billing_address.full_name.blank?
|
205
|
-
self.billing_address.full_name = billing_name
|
206
|
-
end
|
207
|
-
|
208
|
-
if shipping_address.present? && shipping_address.full_name.blank?
|
209
|
-
self.shipping_address.full_name = billing_name
|
210
|
-
end
|
194
|
+
user
|
211
195
|
end
|
212
196
|
|
213
197
|
# This is called from admin/orders#create
|
214
198
|
# This is intended for use as an admin action only
|
215
199
|
# It skips any address or bad user validations
|
216
|
-
def create_as_pending
|
200
|
+
def create_as_pending!
|
201
|
+
return false unless new_record?
|
202
|
+
|
217
203
|
self.purchase_state = EffectiveOrders::PENDING
|
218
204
|
|
219
205
|
self.skip_buyer_validations = true
|
220
206
|
self.addresses.clear if addresses.any? { |address| address.valid? == false }
|
221
207
|
|
222
|
-
|
208
|
+
save!
|
223
209
|
|
224
210
|
send_payment_request_to_buyer! if send_payment_request_to_buyer?
|
211
|
+
|
225
212
|
true
|
226
213
|
end
|
227
214
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
order_item = self.order_items.find { |oi| oi.purchasable.class.name == atts[:class] && oi.purchasable.id == atts[:id].to_i }
|
238
|
-
|
239
|
-
if order_item
|
240
|
-
order_item.purchasable.attributes = atts.except(:id, :class)
|
241
|
-
|
242
|
-
# Recalculate the OrderItem based on the updated purchasable object
|
243
|
-
order_item.title = order_item.purchasable.title
|
244
|
-
order_item.price = order_item.purchasable.price
|
245
|
-
order_item.tax_exempt = order_item.purchasable.tax_exempt
|
246
|
-
order_item.seller_id = (order_item.purchasable.try(:seller).try(:id) rescue nil)
|
247
|
-
end
|
248
|
-
end
|
215
|
+
def to_s
|
216
|
+
if refund?
|
217
|
+
"Refund ##{to_param}"
|
218
|
+
elsif purchased?
|
219
|
+
"Receipt ##{to_param}"
|
220
|
+
elsif pending?
|
221
|
+
"Pending Order ##{to_param}"
|
222
|
+
else
|
223
|
+
"Order ##{to_param}"
|
249
224
|
end
|
250
225
|
end
|
251
226
|
|
227
|
+
def free?
|
228
|
+
total == 0
|
229
|
+
end
|
230
|
+
|
231
|
+
def refund?
|
232
|
+
total.to_i < 0
|
233
|
+
end
|
234
|
+
|
252
235
|
def purchasables
|
253
236
|
order_items.map { |order_item| order_item.purchasable }
|
254
237
|
end
|
@@ -266,31 +249,27 @@ module Effective
|
|
266
249
|
end
|
267
250
|
|
268
251
|
def total
|
269
|
-
self[:total] ||
|
252
|
+
(self[:total] || (subtotal + tax.to_i)).to_i
|
270
253
|
end
|
271
254
|
|
272
255
|
def num_items
|
273
256
|
order_items.map { |oi| oi.quantity }.sum
|
274
257
|
end
|
275
258
|
|
276
|
-
def save_billing_address?
|
277
|
-
truthy?(self.save_billing_address)
|
278
|
-
end
|
279
|
-
|
280
|
-
def save_shipping_address?
|
281
|
-
truthy?(self.save_shipping_address)
|
282
|
-
end
|
283
|
-
|
284
259
|
def send_payment_request_to_buyer?
|
285
|
-
truthy?(
|
260
|
+
truthy?(send_payment_request_to_buyer)
|
286
261
|
end
|
287
262
|
|
288
263
|
def send_mark_as_paid_email_to_buyer?
|
289
|
-
truthy?(
|
264
|
+
truthy?(send_mark_as_paid_email_to_buyer)
|
290
265
|
end
|
291
266
|
|
292
267
|
def skip_buyer_validations?
|
293
|
-
truthy?(
|
268
|
+
truthy?(skip_buyer_validations)
|
269
|
+
end
|
270
|
+
|
271
|
+
def skip_minimum_charge_validation?
|
272
|
+
truthy?(skip_minimum_charge_validation) || skip_buyer_validations?
|
294
273
|
end
|
295
274
|
|
296
275
|
def billing_name
|
@@ -309,6 +288,7 @@ module Effective
|
|
309
288
|
return false if purchased?
|
310
289
|
|
311
290
|
success = false
|
291
|
+
error = nil
|
312
292
|
|
313
293
|
Effective::Order.transaction do
|
314
294
|
begin
|
@@ -321,23 +301,27 @@ module Effective
|
|
321
301
|
|
322
302
|
self.skip_buyer_validations = skip_buyer_validations
|
323
303
|
|
324
|
-
|
304
|
+
run_purchasable_callbacks(:before_purchase)
|
325
305
|
|
326
|
-
|
306
|
+
save!(validate: validate)
|
327
307
|
|
328
308
|
success = true
|
329
309
|
rescue => e
|
330
310
|
self.purchase_state = purchase_state_was
|
331
311
|
self.purchased_at = purchased_at_was
|
332
312
|
|
313
|
+
error = e.message
|
333
314
|
raise ::ActiveRecord::Rollback
|
334
315
|
end
|
335
316
|
end
|
336
317
|
|
337
|
-
|
318
|
+
raise "Failed to purchase Effective::Order: #{error || errors.full_messages.to_sentence}" unless success
|
319
|
+
|
320
|
+
send_order_receipts! if email
|
338
321
|
|
339
|
-
|
340
|
-
|
322
|
+
run_purchasable_callbacks(:after_purchase)
|
323
|
+
|
324
|
+
true
|
341
325
|
end
|
342
326
|
|
343
327
|
def decline!(details: 'none', provider: 'none', card: 'none', validate: true)
|
@@ -346,6 +330,7 @@ module Effective
|
|
346
330
|
raise EffectiveOrders::AlreadyPurchasedException.new('order already purchased') if purchased?
|
347
331
|
|
348
332
|
success = false
|
333
|
+
error = nil
|
349
334
|
|
350
335
|
Effective::Order.transaction do
|
351
336
|
begin
|
@@ -358,16 +343,25 @@ module Effective
|
|
358
343
|
|
359
344
|
save!(validate: validate)
|
360
345
|
|
361
|
-
order_items.each { |item| (item.purchasable.declined!(self, item) rescue nil) }
|
362
|
-
|
363
346
|
success = true
|
364
347
|
rescue => e
|
348
|
+
self.purchase_state = purchase_state_was
|
349
|
+
self.purchased_at = purchased_at_was
|
350
|
+
|
351
|
+
error = e.message
|
365
352
|
raise ::ActiveRecord::Rollback
|
366
353
|
end
|
367
354
|
end
|
368
355
|
|
369
|
-
raise "Failed to decline! Effective::Order: #{
|
370
|
-
|
356
|
+
raise "Failed to decline! Effective::Order: #{error || errors.full_messages.to_sentence}" unless success
|
357
|
+
|
358
|
+
run_purchasable_callbacks(:after_decline)
|
359
|
+
|
360
|
+
true
|
361
|
+
end
|
362
|
+
|
363
|
+
def abandoned?
|
364
|
+
purchase_state == EffectiveOrders::ABANDONED
|
371
365
|
end
|
372
366
|
|
373
367
|
def purchased?(provider = nil)
|
@@ -404,17 +398,17 @@ module Effective
|
|
404
398
|
def send_order_receipt_to_seller!
|
405
399
|
return false unless (EffectiveOrders.stripe_connect_enabled && purchased?(:stripe_connect))
|
406
400
|
|
407
|
-
order_items.group_by
|
401
|
+
order_items.group_by { |oi| oi.seller }.each do |seller, order_items|
|
408
402
|
send_email(:order_receipt_to_seller, to_param, seller, order_items)
|
409
403
|
end
|
410
404
|
end
|
411
405
|
|
412
406
|
def send_payment_request_to_buyer!
|
413
|
-
send_email(:payment_request_to_buyer, to_param)
|
407
|
+
send_email(:payment_request_to_buyer, to_param) unless purchased?
|
414
408
|
end
|
415
409
|
|
416
410
|
def send_pending_order_invoice_to_buyer!
|
417
|
-
send_email(:pending_order_invoice_to_buyer, to_param)
|
411
|
+
send_email(:pending_order_invoice_to_buyer, to_param) unless purchased?
|
418
412
|
end
|
419
413
|
|
420
414
|
protected
|
@@ -430,8 +424,7 @@ module Effective
|
|
430
424
|
|
431
425
|
def get_tax
|
432
426
|
return nil unless tax_rate.present?
|
433
|
-
|
434
|
-
[amount, 0].max
|
427
|
+
order_items.reject { |oi| oi.tax_exempt? }.map { |oi| (oi.subtotal * (tax_rate / 100.0)).round(0).to_i }.sum
|
435
428
|
end
|
436
429
|
|
437
430
|
private
|
@@ -440,7 +433,27 @@ module Effective
|
|
440
433
|
self.subtotal = order_items.map { |oi| oi.subtotal }.sum
|
441
434
|
self.tax_rate = get_tax_rate()
|
442
435
|
self.tax = get_tax()
|
443
|
-
self.total =
|
436
|
+
self.total = subtotal + (tax || 0)
|
437
|
+
end
|
438
|
+
|
439
|
+
def save_addresses
|
440
|
+
if user.respond_to?(:billing_address=) && billing_address.present?
|
441
|
+
user.billing_address = billing_address
|
442
|
+
user.billing_address.save
|
443
|
+
end
|
444
|
+
|
445
|
+
if user.respond_to?(:shipping_address=) && shipping_address.present?
|
446
|
+
user.shipping_address = shipping_address
|
447
|
+
user.shipping_address.save
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
def run_purchasable_callbacks(name)
|
452
|
+
begin
|
453
|
+
order_items.each { |oi| oi.purchasable.public_send(name, self, oi) if oi.purchasable.respond_to?(name) }
|
454
|
+
rescue => e
|
455
|
+
raise e unless Rails.env.production?
|
456
|
+
end
|
444
457
|
end
|
445
458
|
|
446
459
|
def send_email(email, *mailer_args)
|