effective_orders 5.0.1 → 5.1.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/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
|