effective_orders 5.0.1 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +67 -1
- data/app/assets/config/effective_orders_manifest.js +3 -0
- data/app/assets/images/effective_orders/logo.png +0 -0
- data/app/assets/javascripts/effective_orders.js +1 -1
- data/app/assets/javascripts/effective_orders/providers/moneris_checkout.js.coffee +71 -0
- data/app/assets/stylesheets/effective_orders/_order.scss +4 -0
- data/app/controllers/effective/concerns/purchase.rb +14 -21
- data/app/controllers/effective/orders_controller.rb +2 -2
- data/app/controllers/effective/providers/free.rb +0 -1
- data/app/controllers/effective/providers/mark_as_paid.rb +1 -2
- data/app/controllers/effective/providers/moneris_checkout.rb +59 -0
- data/app/controllers/effective/providers/pretend.rb +1 -2
- data/app/controllers/effective/providers/refund.rb +1 -2
- data/app/controllers/effective/providers/stripe.rb +1 -2
- data/app/datatables/admin/effective_orders_datatable.rb +5 -8
- data/app/datatables/effective_orders_datatable.rb +3 -7
- data/app/helpers/effective_moneris_checkout_helper.rb +65 -0
- data/app/helpers/effective_orders_helper.rb +3 -26
- data/app/mailers/effective/orders_mailer.rb +6 -4
- data/app/models/concerns/acts_as_purchasable.rb +2 -0
- data/app/models/concerns/acts_as_subscribable.rb +1 -0
- data/app/models/concerns/acts_as_subscribable_buyer.rb +2 -1
- data/app/models/effective/order.rb +56 -35
- data/app/models/effective/order_item.rb +10 -0
- data/app/models/effective/product.rb +2 -0
- data/app/views/effective/orders/_checkout_step2.html.haml +3 -0
- data/app/views/effective/orders/_order.html.haml +1 -1
- data/app/views/effective/orders/_order_actions.html.haml +1 -1
- data/app/views/effective/orders/_order_footer.html.haml +3 -1
- data/app/views/effective/orders/_order_header.html.haml +4 -20
- data/app/views/effective/orders/_order_payment.html.haml +7 -18
- data/app/views/effective/orders/declined.html.haml +2 -4
- data/app/views/effective/orders/deferred.html.haml +2 -4
- data/app/views/effective/orders/moneris_checkout/_element.html.haml +4 -0
- data/app/views/effective/orders/moneris_checkout/_form.html.haml +23 -0
- data/app/views/effective/orders/purchased.html.haml +2 -4
- data/app/views/effective/orders/show.html.haml +5 -2
- data/config/effective_orders.rb +19 -0
- data/config/routes.rb +1 -0
- data/lib/effective_orders.rb +23 -2
- data/lib/effective_orders/engine.rb +2 -2
- data/lib/effective_orders/version.rb +1 -1
- data/lib/generators/templates/effective_orders_mailer_preview.rb +6 -0
- metadata +69 -6
@@ -0,0 +1,65 @@
|
|
1
|
+
module EffectiveMonerisCheckoutHelper
|
2
|
+
|
3
|
+
def moneris_checkout_preload_request(order)
|
4
|
+
# Make the Preload Request
|
5
|
+
params = {
|
6
|
+
# Required
|
7
|
+
environment: EffectiveOrders.moneris_checkout.fetch(:environment),
|
8
|
+
|
9
|
+
api_token: EffectiveOrders.moneris_checkout.fetch(:api_token),
|
10
|
+
store_id: EffectiveOrders.moneris_checkout.fetch(:store_id),
|
11
|
+
checkout_id: EffectiveOrders.moneris_checkout.fetch(:checkout_id),
|
12
|
+
|
13
|
+
action: :preload,
|
14
|
+
txn_total: price_to_currency(order.total).gsub(',', '').gsub('$', ''),
|
15
|
+
|
16
|
+
# Optional
|
17
|
+
order_no: order.transaction_id, # Has to be unique. This is order number, billing name and Time.now
|
18
|
+
cust_id: order.user_id,
|
19
|
+
language: 'en',
|
20
|
+
|
21
|
+
contact_details: {
|
22
|
+
first_name: order.billing_first_name,
|
23
|
+
last_name: order.billing_last_name,
|
24
|
+
email: order.email,
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
if (address = order.billing_address).present?
|
29
|
+
params.merge!(
|
30
|
+
billing_details: {
|
31
|
+
address_1: address.address1,
|
32
|
+
address_2: address.address2,
|
33
|
+
city: address.city,
|
34
|
+
province: address.state_code,
|
35
|
+
country: address.country_code,
|
36
|
+
postal_code: address.postal_code
|
37
|
+
}
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
if (address = order.shipping_address).present?
|
42
|
+
params.merge!(
|
43
|
+
shipping_details: {
|
44
|
+
address_1: address.address1,
|
45
|
+
address_2: address.address2,
|
46
|
+
city: address.city,
|
47
|
+
province: address.state_code,
|
48
|
+
country: address.country_code,
|
49
|
+
postal_code: address.postal_code
|
50
|
+
}
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
response = Effective::Http.post(EffectiveOrders.moneris_request_url, params: params)
|
55
|
+
preload = response['response'] if response
|
56
|
+
|
57
|
+
raise("moneris preload error #{response}") unless preload && preload['success'].to_s == 'true'
|
58
|
+
|
59
|
+
payload = {
|
60
|
+
environment: EffectiveOrders.moneris_checkout.fetch(:environment),
|
61
|
+
ticket: preload['ticket']
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -42,6 +42,8 @@ module EffectiveOrdersHelper
|
|
42
42
|
'Admin: Mark as Paid'
|
43
43
|
when :moneris
|
44
44
|
'Checkout with Credit Card'
|
45
|
+
when :moneris_checkout
|
46
|
+
'Pay Now' # Doesn't get displayed anyway
|
45
47
|
when :paypal
|
46
48
|
'Checkout with PayPal'
|
47
49
|
when :phone
|
@@ -107,35 +109,10 @@ module EffectiveOrdersHelper
|
|
107
109
|
end
|
108
110
|
end
|
109
111
|
|
110
|
-
def render_orders(
|
111
|
-
orders = Array(obj.kind_of?(User) ? Effective::Order.purchased_by(obj) : obj)
|
112
|
-
|
113
|
-
if orders.any? { |order| order.kind_of?(Effective::Order) == false }
|
114
|
-
raise 'expected a User or Effective::Order'
|
115
|
-
end
|
116
|
-
|
112
|
+
def render_orders(orders, opts = {})
|
117
113
|
render(partial: 'effective/orders/orders_table', locals: { orders: orders }.merge(opts))
|
118
114
|
end
|
119
115
|
|
120
|
-
def payment_card_label(card)
|
121
|
-
card = card.to_s.downcase.gsub(' ', '').strip
|
122
|
-
|
123
|
-
case card
|
124
|
-
when ''
|
125
|
-
'None'
|
126
|
-
when 'v', 'visa'
|
127
|
-
'Visa'
|
128
|
-
when 'm', 'mc', 'master', 'mastercard'
|
129
|
-
'MasterCard'
|
130
|
-
when 'a', 'ax', 'american', 'americanexpress'
|
131
|
-
'American Express'
|
132
|
-
when 'd', 'discover'
|
133
|
-
'Discover'
|
134
|
-
else
|
135
|
-
card.to_s
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
116
|
def checkout_icon_to(path, options = {})
|
140
117
|
icon_to('shopping-cart', path, { title: 'Checkout' }.merge(options))
|
141
118
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Effective
|
2
2
|
class OrdersMailer < ActionMailer::Base
|
3
|
-
default from: -> { EffectiveOrders.mailer[:default_from] }
|
3
|
+
default from: -> { EffectiveOrders.mailer[:default_from].presence }
|
4
|
+
default cc: -> { EffectiveOrders.mailer[:default_cc].presence }
|
5
|
+
default bcc: -> { EffectiveOrders.mailer[:default_bcc].presence }
|
4
6
|
layout -> { EffectiveOrders.mailer[:layout].presence || 'effective_orders_mailer_layout' }
|
5
7
|
|
6
8
|
helper EffectiveOrdersHelper
|
@@ -27,7 +29,7 @@ module Effective
|
|
27
29
|
|
28
30
|
@subject = subject_for(@order, :order_receipt_to_buyer, "Order Receipt: ##{@order.to_param}")
|
29
31
|
|
30
|
-
mail(to: @order.email, cc: @order.cc, subject: @subject)
|
32
|
+
mail({to: @order.email, cc: @order.cc, subject: @subject}.compact)
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
@@ -43,7 +45,7 @@ module Effective
|
|
43
45
|
|
44
46
|
@subject = subject_for(@order, :payment_request_to_buyer, "Request for Payment: Invoice ##{@order.to_param}")
|
45
47
|
|
46
|
-
mail(to: @order.email, cc: @order.cc, subject: @subject)
|
48
|
+
mail({to: @order.email, cc: @order.cc, subject: @subject}.compact)
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
@@ -58,7 +60,7 @@ module Effective
|
|
58
60
|
|
59
61
|
@subject = subject_for(@order, :pending_order_invoice_to_buyer, "Pending Order: ##{@order.to_param}")
|
60
62
|
|
61
|
-
mail(to: @order.email, cc: @order.cc, subject: @subject)
|
63
|
+
mail({to: @order.email, cc: @order.cc, subject: @subject}.compact)
|
62
64
|
end
|
63
65
|
end
|
64
66
|
|
@@ -19,6 +19,8 @@ module ActsAsSubscribableBuyer
|
|
19
19
|
end
|
20
20
|
|
21
21
|
module ClassMethods
|
22
|
+
def acts_as_subscribable_buyer?; true; end
|
23
|
+
|
22
24
|
def after_invoice_payment_succeeded(&block)
|
23
25
|
send :define_method, :after_invoice_payment_succeeded do |event| self.instance_exec(event, &block) end
|
24
26
|
end
|
@@ -46,4 +48,3 @@ module ActsAsSubscribableBuyer
|
|
46
48
|
end
|
47
49
|
|
48
50
|
end
|
49
|
-
|
@@ -34,10 +34,6 @@ module Effective
|
|
34
34
|
belongs_to :user, polymorphic: true, validate: false # This is the buyer/user of the order. We validate it below.
|
35
35
|
has_many :order_items, -> { order(:id) }, inverse_of: :order, dependent: :delete_all
|
36
36
|
|
37
|
-
if defined?(EffectiveQbSync)
|
38
|
-
has_one :qb_order_item
|
39
|
-
end
|
40
|
-
|
41
37
|
accepts_nested_attributes_for :order_items, allow_destroy: false, reject_if: :all_blank
|
42
38
|
accepts_nested_attributes_for :user, allow_destroy: false, update_only: true
|
43
39
|
|
@@ -141,7 +137,7 @@ module Effective
|
|
141
137
|
validates :payment_provider, presence: true, inclusion: { in: EffectiveOrders.deferred_providers }
|
142
138
|
end
|
143
139
|
|
144
|
-
scope :deep, -> { includes(:user, order_items: :purchasable) }
|
140
|
+
scope :deep, -> { includes(:addresses, :user, order_items: :purchasable) }
|
145
141
|
scope :sorted, -> { order(:id) }
|
146
142
|
|
147
143
|
scope :purchased, -> { where(state: EffectiveOrders::PURCHASED) }
|
@@ -254,21 +250,52 @@ module Effective
|
|
254
250
|
end
|
255
251
|
|
256
252
|
def to_s
|
253
|
+
[label, ' #', to_param].join
|
254
|
+
end
|
255
|
+
|
256
|
+
def label
|
257
257
|
if refund?
|
258
|
-
"Refund
|
258
|
+
"Refund"
|
259
259
|
elsif purchased?
|
260
|
-
"Receipt
|
260
|
+
"Receipt"
|
261
261
|
elsif pending?
|
262
|
-
"Pending Order
|
262
|
+
"Pending Order"
|
263
263
|
else
|
264
|
-
"Order
|
264
|
+
"Order"
|
265
265
|
end
|
266
266
|
end
|
267
267
|
|
268
|
-
#
|
269
|
-
def
|
270
|
-
|
271
|
-
|
268
|
+
# Visa - 1234
|
269
|
+
def payment_method
|
270
|
+
return nil unless purchased?
|
271
|
+
|
272
|
+
# Normalize payment card
|
273
|
+
card = case payment_card.to_s.downcase.gsub(' ', '').strip
|
274
|
+
when '' then nil
|
275
|
+
when 'v', 'visa' then 'Visa'
|
276
|
+
when 'm', 'mc', 'master', 'mastercard' then 'MasterCard'
|
277
|
+
when 'a', 'ax', 'american', 'americanexpress' then 'American Express'
|
278
|
+
when 'd', 'discover' then 'Discover'
|
279
|
+
else payment_card.to_s
|
280
|
+
end unless payment_provider == 'free'
|
281
|
+
|
282
|
+
# stripe, moneris, moneris_checkout
|
283
|
+
last4 = (payment[:active_card] || payment['f4l4'] || payment['first6last4']).to_s.last(4)
|
284
|
+
|
285
|
+
[card, '-', last4].compact.join(' ')
|
286
|
+
end
|
287
|
+
|
288
|
+
# For moneris and moneris_checkout. Just a unique value.
|
289
|
+
def transaction_id
|
290
|
+
[to_param, billing_name.to_s.parameterize.presence, Time.zone.now.to_i].compact.join('-')
|
291
|
+
end
|
292
|
+
|
293
|
+
def billing_first_name
|
294
|
+
billing_name.to_s.split(' ').first
|
295
|
+
end
|
296
|
+
|
297
|
+
def billing_last_name
|
298
|
+
Array(billing_name.to_s.split(' ')[1..-1]).join(' ')
|
272
299
|
end
|
273
300
|
|
274
301
|
def pending?
|
@@ -372,38 +399,31 @@ module Effective
|
|
372
399
|
|
373
400
|
# Effective::Order.new(items: Product.first, user: User.first).purchase!(email: false)
|
374
401
|
def purchase!(payment: 'none', provider: 'none', card: 'none', email: true, skip_buyer_validations: false)
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
assign_attributes(
|
379
|
-
state: EffectiveOrders::PURCHASED,
|
380
|
-
payment: payment_to_h(payment),
|
381
|
-
payment_provider: provider,
|
382
|
-
payment_card: (card.presence || 'none'),
|
383
|
-
skip_buyer_validations: skip_buyer_validations
|
384
|
-
)
|
402
|
+
# Assign attributes
|
403
|
+
self.state = EffectiveOrders::PURCHASED
|
404
|
+
self.skip_buyer_validations = skip_buyer_validations
|
385
405
|
|
406
|
+
self.payment_provider ||= provider
|
407
|
+
self.payment_card ||= (card.presence || 'none')
|
386
408
|
self.purchased_at ||= Time.zone.now
|
409
|
+
self.payment = payment_to_h(payment) if self.payment.blank?
|
387
410
|
|
388
|
-
|
389
|
-
|
411
|
+
begin
|
412
|
+
Effective::Order.transaction do
|
390
413
|
run_purchasable_callbacks(:before_purchase)
|
391
414
|
save!
|
392
415
|
update_purchasables_purchased_order!
|
393
|
-
rescue => e
|
394
|
-
self.state = state_was
|
395
|
-
self.purchased_at = nil
|
396
|
-
|
397
|
-
error = e.message
|
398
|
-
raise ::ActiveRecord::Rollback
|
399
416
|
end
|
400
|
-
|
417
|
+
rescue => e
|
418
|
+
Effective::Order.transaction do
|
419
|
+
save!(validate: false)
|
420
|
+
update_purchasables_purchased_order!
|
421
|
+
end
|
401
422
|
|
402
|
-
|
423
|
+
raise(e)
|
424
|
+
end
|
403
425
|
|
404
426
|
run_purchasable_callbacks(:after_purchase)
|
405
|
-
|
406
|
-
send_refund_notification! if email && refund?
|
407
427
|
send_order_receipts! if email
|
408
428
|
|
409
429
|
true
|
@@ -466,6 +486,7 @@ module Effective
|
|
466
486
|
def send_order_receipts!
|
467
487
|
send_order_receipt_to_admin! if EffectiveOrders.mailer[:send_order_receipt_to_admin]
|
468
488
|
send_order_receipt_to_buyer! if EffectiveOrders.mailer[:send_order_receipt_to_buyer]
|
489
|
+
send_refund_notification! if refund?
|
469
490
|
end
|
470
491
|
|
471
492
|
def send_order_receipt_to_admin!
|
@@ -5,6 +5,10 @@ module Effective
|
|
5
5
|
belongs_to :order
|
6
6
|
belongs_to :purchasable, polymorphic: true
|
7
7
|
|
8
|
+
if defined?(EffectiveQbSync)
|
9
|
+
has_one :qb_order_item
|
10
|
+
end
|
11
|
+
|
8
12
|
effective_resource do
|
9
13
|
name :string
|
10
14
|
quantity :integer
|
@@ -61,5 +65,11 @@ module Effective
|
|
61
65
|
end
|
62
66
|
end
|
63
67
|
|
68
|
+
# first or build
|
69
|
+
def qb_item_name
|
70
|
+
raise('expected EffectiveQbSync gem') unless defined?(EffectiveQbSync)
|
71
|
+
(qb_order_item || build_qb_order_item(name: purchasable.qb_item_name)).name
|
72
|
+
end
|
73
|
+
|
64
74
|
end
|
65
75
|
end
|
@@ -20,6 +20,9 @@
|
|
20
20
|
- if EffectiveOrders.moneris?
|
21
21
|
= render partial: '/effective/orders/moneris/form', locals: provider_locals
|
22
22
|
|
23
|
+
- if EffectiveOrders.moneris_checkout?
|
24
|
+
= render partial: '/effective/orders/moneris_checkout/form', locals: provider_locals
|
25
|
+
|
23
26
|
- if EffectiveOrders.paypal?
|
24
27
|
= render partial: '/effective/orders/paypal/form', locals: provider_locals
|
25
28
|
|
@@ -3,9 +3,9 @@
|
|
3
3
|
= render partial: 'effective/orders/order_actions', locals: { order: order }
|
4
4
|
|
5
5
|
= render partial: 'effective/orders/order_header', locals: { order: order }
|
6
|
+
= render partial: 'effective/orders/order_payment', locals: { order: order }
|
6
7
|
= render partial: 'effective/orders/order_shipping', locals: { order: order }
|
7
8
|
= render partial: 'effective/orders/order_deferred', locals: { order: order }
|
8
9
|
= render partial: 'effective/orders/order_notes', locals: { order: order }
|
9
10
|
= render partial: 'effective/orders/order_items', locals: { order: order }
|
10
|
-
= render partial: 'effective/orders/order_payment', locals: { order: order }
|
11
11
|
= render partial: 'effective/orders/order_footer', locals: { order: order }
|
@@ -3,7 +3,7 @@
|
|
3
3
|
= link_to 'Print', '#', class: 'btn btn-primary print-button', data: { role: 'print-button' }, onClick: 'window.print(); false;'
|
4
4
|
|
5
5
|
- if order.purchased?
|
6
|
-
= link_to '
|
6
|
+
= link_to 'E-mail Receipt', effective_orders.send_buyer_receipt_order_path(order),
|
7
7
|
class: 'btn btn-secondary',
|
8
8
|
data: { confirm: "Send receipt to #{order.emails_send_to}?" }
|
9
9
|
|
@@ -1,23 +1,7 @@
|
|
1
1
|
.effective-order-header
|
2
|
-
|
3
|
-
|
4
|
-
.col-sm-6
|
5
|
-
- email_address = EffectiveOrders.mailer[:admin_email] || 'info@acmeindustries.com'
|
6
|
-
%p= mail_to u(email_address), email_address
|
7
|
-
%p
|
8
|
-
1234 Fake Street
|
9
|
-
%br
|
10
|
-
Edmonton, AB, T5H 4A5
|
11
|
-
%br
|
12
|
-
%small Customize me by overriding '/app/views/effective/orders/_order_header.html.haml'
|
2
|
+
.mb-4.text-center
|
3
|
+
= image_tag('effective_orders/logo.png')
|
13
4
|
|
14
|
-
.
|
15
|
-
- if order.purchased?
|
16
|
-
%p Receipt: ##{order.to_param}
|
17
|
-
- elsif order.persisted?
|
18
|
-
%p Order: ##{order.to_param}
|
5
|
+
%h2 #{order.label} from Example Inc.
|
19
6
|
|
20
|
-
|
21
|
-
%p Purchased at: #{order.purchased_at.strftime("%F %H:%M")}
|
22
|
-
- else
|
23
|
-
%p Date: #{Time.zone.now.strftime("%F %H:%M")}
|
7
|
+
%p.text-muted= order.to_s
|
@@ -1,24 +1,13 @@
|
|
1
1
|
- if order.purchased?
|
2
|
-
.effective-order-payment
|
2
|
+
.effective-order-payment
|
3
3
|
%table.table
|
4
4
|
%thead
|
5
5
|
%tr
|
6
|
-
%th
|
7
|
-
%th
|
6
|
+
%th Amount Paid
|
7
|
+
%th Date Paid
|
8
|
+
%th Payment Method
|
8
9
|
%tbody
|
9
10
|
%tr
|
10
|
-
%td
|
11
|
-
%td= order.
|
12
|
-
|
13
|
-
- if order.payment_card.present?
|
14
|
-
%tr
|
15
|
-
%td Card
|
16
|
-
%td
|
17
|
-
= payment_card_label(order.payment_card)
|
18
|
-
- if order.payment.kind_of?(Hash)
|
19
|
-
= order.payment[:active_card] || order.payment['f4l4']
|
20
|
-
|
21
|
-
%tr
|
22
|
-
%td Purchased at
|
23
|
-
%td= order.purchased_at&.strftime('%F %H:%M')
|
24
|
-
|
11
|
+
%td= price_to_currency(order.total)
|
12
|
+
%td= order.purchased_at.strftime('%b %d, %Y')
|
13
|
+
%td= order.payment_method
|