effective_orders 5.0.3 → 5.1.1
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/providers/moneris_checkout.js.coffee +71 -0
- data/app/assets/javascripts/effective_orders.js +1 -1
- data/app/assets/stylesheets/effective_orders/_order.scss +4 -0
- data/app/controllers/effective/concerns/purchase.rb +3 -3
- data/app/controllers/effective/orders_controller.rb +1 -0
- data/app/controllers/effective/providers/moneris_checkout.rb +59 -0
- data/app/datatables/admin/effective_orders_datatable.rb +5 -8
- data/app/datatables/effective_orders_datatable.rb +3 -5
- data/app/helpers/effective_moneris_checkout_helper.rb +65 -0
- data/app/helpers/effective_orders_helper.rb +2 -19
- 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 +42 -11
- 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_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 +4 -5
- data/config/effective_orders.rb +19 -0
- data/config/routes.rb +1 -0
- data/lib/effective_orders/engine.rb +2 -2
- data/lib/effective_orders/version.rb +1 -1
- data/lib/effective_orders.rb +23 -2
- data/lib/generators/templates/effective_orders_mailer_preview.rb +6 -0
- metadata +69 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78aa25d8f77169e21e2f05886c47479ac2f64d8de4657510b2723ab9d4246fbd
|
4
|
+
data.tar.gz: 22f9fd8d7747c3975952fe6edfc6e221fe567ec0b287e619ba3afd861dcc2bfb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c3d9e1dcc47b3f982be6bc41abbafde4ceae73b682704f0916b941aa06248d431b52420d472592e850919e518bc12b835be04fdee5292d9d72396ebe9b053fe
|
7
|
+
data.tar.gz: 7ff135bb56772c9fdf3edf6d59dc4ef7e0dfade542b1db022b09db49fc2b9b7e9f7333ae5e705390b4b0f27a03127fb743c9ffb471b29dd74e4a6a3da75917d0
|
data/README.md
CHANGED
@@ -594,8 +594,74 @@ You will need an external IP address to work with these sandboxes.
|
|
594
594
|
|
595
595
|
We suggest the free application `https://ngrok.com/` for this ability.
|
596
596
|
|
597
|
+
## Paying with Moneris Checkout
|
597
598
|
|
598
|
-
|
599
|
+
Use the following instructions to set up a Moneris Checkout store.
|
600
|
+
|
601
|
+
This is the javascript / pay in place form implementation.
|
602
|
+
|
603
|
+
We do not use or implement tokenization of credentials with Moneris Checkout.
|
604
|
+
|
605
|
+
We are also going to use ngrok to give us a public facing URL
|
606
|
+
|
607
|
+
### Create Test / Development Store
|
608
|
+
|
609
|
+
Visit https://esqa.moneris.com/mpg/ and login with: demouser / store1 / password
|
610
|
+
|
611
|
+
- Select Admin -> Moneris Checkout Config from the menu
|
612
|
+
- Click Create Profile
|
613
|
+
|
614
|
+
Checkout Type: I have my custom order form and want to use Moneris simply for payment processing
|
615
|
+
|
616
|
+
Multi-Currency: None
|
617
|
+
|
618
|
+
Payment:
|
619
|
+
|
620
|
+
- Google Pay: No
|
621
|
+
- Card Logos: Yes
|
622
|
+
- Payment Security: CVV
|
623
|
+
- Transaction Type: Purchase
|
624
|
+
- Transaction Limits: None
|
625
|
+
|
626
|
+
Branding & Design
|
627
|
+
|
628
|
+
- Logo Url: None
|
629
|
+
- Colors: Default
|
630
|
+
|
631
|
+
Customizations
|
632
|
+
|
633
|
+
- Enable Fullscreen: No false (important)
|
634
|
+
- Card Borders/Shadows: Yes
|
635
|
+
|
636
|
+
Order Confirmation
|
637
|
+
|
638
|
+
- Order Confirmation Processing: Use Moneris
|
639
|
+
- Confirmation Page Content: Check all
|
640
|
+
|
641
|
+
Email Communications
|
642
|
+
|
643
|
+
- None
|
644
|
+
- Customer Emails: None
|
645
|
+
|
646
|
+
|
647
|
+
Now copy the Checkout id, something like `chktJF76Btore1` into the config/initializers/effective_orders.rb file.
|
648
|
+
|
649
|
+
For the store_id and api_token values, you can use
|
650
|
+
|
651
|
+
```
|
652
|
+
config.moneris_checkout = {
|
653
|
+
environment: 'qa',
|
654
|
+
store_id: 'store1',
|
655
|
+
api_token: 'yesguy1',
|
656
|
+
checkout_id: '', # You need to generate this one
|
657
|
+
}
|
658
|
+
```
|
659
|
+
|
660
|
+
[Testing a Solution](https://developer.moneris.com/en/More/Testing/Testing%20a%20Solution)
|
661
|
+
|
662
|
+
|
663
|
+
|
664
|
+
## Paying via Moneris (hosted pay page - old)
|
599
665
|
|
600
666
|
Use the following instructions to set up a Moneris TEST store.
|
601
667
|
|
Binary file
|
@@ -0,0 +1,71 @@
|
|
1
|
+
this.MonerisCheckoutForm ||= class MonerisCheckoutForm
|
2
|
+
constructor: ->
|
3
|
+
@form = null
|
4
|
+
@data = null
|
5
|
+
@moneris = null
|
6
|
+
|
7
|
+
initialize: ->
|
8
|
+
@form = $('form[data-moneris-checkout-form]:not(.initialized)').first()
|
9
|
+
return false unless @form.length > 0
|
10
|
+
|
11
|
+
@data = @form.data('moneris-checkout-form')
|
12
|
+
@moneris = new monerisCheckout()
|
13
|
+
|
14
|
+
@mount()
|
15
|
+
@form.addClass('initialized')
|
16
|
+
|
17
|
+
mount: ->
|
18
|
+
@moneris.setCheckoutDiv('monerisCheckout')
|
19
|
+
|
20
|
+
@moneris.setCallback('page_loaded', @pageLoaded)
|
21
|
+
@moneris.setCallback('cancel_transaction', @cancelTransaction)
|
22
|
+
@moneris.setCallback('error_event', @errorEvent)
|
23
|
+
@moneris.setCallback('payment_receipt', @paymentReceipt)
|
24
|
+
@moneris.setCallback('payment_complete', @paymentComplete)
|
25
|
+
|
26
|
+
@moneris.setMode(@data.environment)
|
27
|
+
@moneris.startCheckout(@data.ticket)
|
28
|
+
|
29
|
+
success: (payload) ->
|
30
|
+
@moneris.closeCheckout()
|
31
|
+
|
32
|
+
payment = JSON.parse(payload)
|
33
|
+
@form.find('#moneris-checkout-success').html("Transaction complete! Please wait a moment...")
|
34
|
+
@form.find("input[name$='[ticket]']").first().val(payment['ticket'])
|
35
|
+
@form.submit()
|
36
|
+
|
37
|
+
error: (text) ->
|
38
|
+
@moneris.closeCheckout()
|
39
|
+
|
40
|
+
text = "<p>" + text + "<p>Please <a href='#', onclick='window.location.reload();' class='alert-link'>reload the page</a> and try again.</p>"
|
41
|
+
@form.find('#moneris-checkout-error').addClass('alert').html(text)
|
42
|
+
EffectiveForm.invalidate(@form)
|
43
|
+
|
44
|
+
# Moneris iframe has loaded
|
45
|
+
pageLoaded: (payload) =>
|
46
|
+
preload = JSON.parse(payload)
|
47
|
+
|
48
|
+
switch preload['response_code']
|
49
|
+
when '001'
|
50
|
+
true # Success. Nothing to do.
|
51
|
+
when '902'
|
52
|
+
@error('3-D secure failed on response')
|
53
|
+
when '2001'
|
54
|
+
@error('Invalid ticket/ticket re-use')
|
55
|
+
else
|
56
|
+
@error('Unknown payment gateway preload status')
|
57
|
+
|
58
|
+
# Cancel Button
|
59
|
+
cancelTransaction: (payload) => false
|
60
|
+
|
61
|
+
# Any kind of error
|
62
|
+
errorEvent: (payload) =>
|
63
|
+
error = JSON.parse(payload)
|
64
|
+
@error("A payment gateway error #{error['response_code']} has occurred. Your card has not been charged.")
|
65
|
+
|
66
|
+
# Payment is all done
|
67
|
+
paymentReceipt: (payload) => @success(payload)
|
68
|
+
paymentComplete: (payload) => @success(payload)
|
69
|
+
|
70
|
+
$ -> (new MonerisCheckoutForm()).initialize()
|
71
|
+
$(document).on 'turbolinks:load', -> (new MonerisCheckoutForm()).initialize()
|
@@ -18,7 +18,7 @@ module Effective
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
purchased_url
|
21
|
+
purchased_url = effective_orders.purchased_order_path(':id') if purchased_url.blank?
|
22
22
|
redirect_to purchased_url.gsub(':id', @order.to_param.to_s)
|
23
23
|
end
|
24
24
|
|
@@ -35,7 +35,7 @@ module Effective
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
deferred_url
|
38
|
+
deferred_url = effective_orders.deferred_order_path(':id') if deferred_url.blank?
|
39
39
|
redirect_to deferred_url.gsub(':id', @order.to_param.to_s)
|
40
40
|
end
|
41
41
|
|
@@ -46,7 +46,7 @@ module Effective
|
|
46
46
|
flash[:danger] = 'Payment was unsuccessful. Your credit card was declined by the payment processor. Please try again.'
|
47
47
|
end
|
48
48
|
|
49
|
-
declined_url
|
49
|
+
declined_url = effective_orders.declined_order_path(':id') if declined_url.blank?
|
50
50
|
redirect_to declined_url.gsub(':id', @order.to_param.to_s)
|
51
51
|
end
|
52
52
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Effective
|
2
|
+
module Providers
|
3
|
+
module MonerisCheckout
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def moneris_checkout
|
7
|
+
raise('moneris_checkout provider is not available') unless EffectiveOrders.moneris_checkout?
|
8
|
+
|
9
|
+
@order = Order.find(params[:id])
|
10
|
+
(EffectiveResources.authorize!(self, :update, @order) rescue false)
|
11
|
+
|
12
|
+
payment = moneris_checkout_receipt_request(moneris_checkout_params[:ticket])
|
13
|
+
purchased = (1..49).include?(payment['response_code'].to_i) # Must be > 0 and < 50 to be valid. Sometimes we get the string 'null'
|
14
|
+
|
15
|
+
if purchased == false
|
16
|
+
return order_declined(
|
17
|
+
payment: payment,
|
18
|
+
provider: 'moneris_checkout',
|
19
|
+
declined_url: moneris_checkout_params[:declined_url]
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
order_purchased(
|
24
|
+
payment: payment,
|
25
|
+
provider: 'moneris_checkout',
|
26
|
+
card: payment['card_type'],
|
27
|
+
purchased_url: moneris_checkout_params[:purchased_url]
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def moneris_checkout_params
|
34
|
+
params.require(:moneris_checkout).permit(:ticket, :purchased_url, :declined_url)
|
35
|
+
end
|
36
|
+
|
37
|
+
def moneris_checkout_receipt_request(ticket)
|
38
|
+
params = {
|
39
|
+
environment: EffectiveOrders.moneris_checkout.fetch(:environment),
|
40
|
+
|
41
|
+
api_token: EffectiveOrders.moneris_checkout.fetch(:api_token),
|
42
|
+
store_id: EffectiveOrders.moneris_checkout.fetch(:store_id),
|
43
|
+
checkout_id: EffectiveOrders.moneris_checkout.fetch(:checkout_id),
|
44
|
+
|
45
|
+
action: :receipt,
|
46
|
+
ticket: ticket
|
47
|
+
}
|
48
|
+
|
49
|
+
response = Effective::Http.post(EffectiveOrders.moneris_request_url, params: params)
|
50
|
+
response = response['response'] if response
|
51
|
+
|
52
|
+
raise("moneris receipt error #{response}") unless response && response['success'].to_s == 'true'
|
53
|
+
|
54
|
+
response.dig('receipt', 'cc') || response.dig('receipt', 'gift') || response
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -14,12 +14,12 @@ class Admin::EffectiveOrdersDatatable < Effective::Datatable
|
|
14
14
|
end
|
15
15
|
|
16
16
|
filters do
|
17
|
-
|
18
|
-
scope :
|
17
|
+
unless attributes[:skip_filters]
|
18
|
+
scope :all
|
19
|
+
scope :purchased
|
19
20
|
scope :deferred
|
20
21
|
scope :refunds
|
21
22
|
scope :not_purchased
|
22
|
-
scope :all
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -84,13 +84,14 @@ class Admin::EffectiveOrdersDatatable < Effective::Datatable
|
|
84
84
|
end
|
85
85
|
|
86
86
|
collection do
|
87
|
-
scope = Effective::Order.all.
|
87
|
+
scope = Effective::Order.all.deep
|
88
88
|
|
89
89
|
if EffectiveOrders.orders_collection_scope.respond_to?(:call)
|
90
90
|
scope = EffectiveOrders.orders_collection_scope.call(scope)
|
91
91
|
end
|
92
92
|
|
93
93
|
if attributes[:user_id].present?
|
94
|
+
user = current_user.class.find(attributes[:user_id])
|
94
95
|
scope = scope.where(user: user)
|
95
96
|
end
|
96
97
|
|
@@ -101,8 +102,4 @@ class Admin::EffectiveOrdersDatatable < Effective::Datatable
|
|
101
102
|
scope
|
102
103
|
end
|
103
104
|
|
104
|
-
def user
|
105
|
-
@user ||= current_user.class.find(attributes[:user_id])
|
106
|
-
end
|
107
|
-
|
108
105
|
end
|
@@ -59,7 +59,9 @@ class EffectiveOrdersDatatable < Effective::Datatable
|
|
59
59
|
end
|
60
60
|
|
61
61
|
collection do
|
62
|
-
|
62
|
+
user = current_user.class.find(attributes[:user_id])
|
63
|
+
|
64
|
+
scope = Effective::Order.all.deep.where(user: user)
|
63
65
|
|
64
66
|
if EffectiveOrders.orders_collection_scope.respond_to?(:call)
|
65
67
|
scope = EffectiveOrders.orders_collection_scope.call(scope)
|
@@ -76,8 +78,4 @@ class EffectiveOrdersDatatable < Effective::Datatable
|
|
76
78
|
scope
|
77
79
|
end
|
78
80
|
|
79
|
-
def user
|
80
|
-
@user ||= view.current_user.class.find(attributes[:user_id])
|
81
|
-
end
|
82
|
-
|
83
81
|
end
|
@@ -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
|
@@ -111,25 +113,6 @@ module EffectiveOrdersHelper
|
|
111
113
|
render(partial: 'effective/orders/orders_table', locals: { orders: orders }.merge(opts))
|
112
114
|
end
|
113
115
|
|
114
|
-
def payment_card_label(card)
|
115
|
-
card = card.to_s.downcase.gsub(' ', '').strip
|
116
|
-
|
117
|
-
case card
|
118
|
-
when ''
|
119
|
-
'None'
|
120
|
-
when 'v', 'visa'
|
121
|
-
'Visa'
|
122
|
-
when 'm', 'mc', 'master', 'mastercard'
|
123
|
-
'MasterCard'
|
124
|
-
when 'a', 'ax', 'american', 'americanexpress'
|
125
|
-
'American Express'
|
126
|
-
when 'd', 'discover'
|
127
|
-
'Discover'
|
128
|
-
else
|
129
|
-
card.to_s
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
116
|
def checkout_icon_to(path, options = {})
|
134
117
|
icon_to('shopping-cart', path, { title: 'Checkout' }.merge(options))
|
135
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
|
-
|
@@ -118,12 +118,6 @@ module Effective
|
|
118
118
|
end
|
119
119
|
end
|
120
120
|
|
121
|
-
with_options if: -> { confirmed? && !skip_buyer_validations? } do
|
122
|
-
if EffectiveOrders.terms_and_conditions
|
123
|
-
validates :terms_and_conditions, presence: true
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
121
|
# When Purchased
|
128
122
|
with_options if: -> { purchased? } do
|
129
123
|
validates :purchased_at, presence: true
|
@@ -137,7 +131,7 @@ module Effective
|
|
137
131
|
validates :payment_provider, presence: true, inclusion: { in: EffectiveOrders.deferred_providers }
|
138
132
|
end
|
139
133
|
|
140
|
-
scope :deep, -> { includes(:user, order_items: :purchasable) }
|
134
|
+
scope :deep, -> { includes(:addresses, :user, order_items: :purchasable) }
|
141
135
|
scope :sorted, -> { order(:id) }
|
142
136
|
|
143
137
|
scope :purchased, -> { where(state: EffectiveOrders::PURCHASED) }
|
@@ -250,17 +244,54 @@ module Effective
|
|
250
244
|
end
|
251
245
|
|
252
246
|
def to_s
|
247
|
+
[label, ' #', to_param].join
|
248
|
+
end
|
249
|
+
|
250
|
+
def label
|
253
251
|
if refund?
|
254
|
-
"Refund
|
252
|
+
"Refund"
|
255
253
|
elsif purchased?
|
256
|
-
"Receipt
|
254
|
+
"Receipt"
|
257
255
|
elsif pending?
|
258
|
-
"Pending Order
|
256
|
+
"Pending Order"
|
259
257
|
else
|
260
|
-
"Order
|
258
|
+
"Order"
|
261
259
|
end
|
262
260
|
end
|
263
261
|
|
262
|
+
# Visa - 1234
|
263
|
+
def payment_method
|
264
|
+
return nil unless purchased?
|
265
|
+
|
266
|
+
# Normalize payment card
|
267
|
+
card = case payment_card.to_s.downcase.gsub(' ', '').strip
|
268
|
+
when '' then nil
|
269
|
+
when 'v', 'visa' then 'Visa'
|
270
|
+
when 'm', 'mc', 'master', 'mastercard' then 'MasterCard'
|
271
|
+
when 'a', 'ax', 'american', 'americanexpress' then 'American Express'
|
272
|
+
when 'd', 'discover' then 'Discover'
|
273
|
+
else payment_card.to_s
|
274
|
+
end unless payment_provider == 'free'
|
275
|
+
|
276
|
+
# stripe, moneris, moneris_checkout
|
277
|
+
last4 = (payment[:active_card] || payment['f4l4'] || payment['first6last4']).to_s.last(4)
|
278
|
+
|
279
|
+
[card, '-', last4].compact.join(' ')
|
280
|
+
end
|
281
|
+
|
282
|
+
# For moneris and moneris_checkout. Just a unique value.
|
283
|
+
def transaction_id
|
284
|
+
[to_param, billing_name.to_s.parameterize.presence, Time.zone.now.to_i].compact.join('-')
|
285
|
+
end
|
286
|
+
|
287
|
+
def billing_first_name
|
288
|
+
billing_name.to_s.split(' ').first
|
289
|
+
end
|
290
|
+
|
291
|
+
def billing_last_name
|
292
|
+
Array(billing_name.to_s.split(' ')[1..-1]).join(' ')
|
293
|
+
end
|
294
|
+
|
264
295
|
def pending?
|
265
296
|
state == EffectiveOrders::PENDING
|
266
297
|
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 }
|
@@ -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
|
@@ -1,12 +1,10 @@
|
|
1
1
|
%h1.effective-heading= @page_title
|
2
2
|
|
3
|
-
%p.effective-orders-page-content
|
4
|
-
= link_to 'Home', root_path
|
5
|
-
|
6
3
|
%p.effective-orders-page-content
|
7
4
|
- if current_cart.present?
|
8
5
|
Your #{link_to_current_cart(label: 'Cart')} items have been saved. Please try again.
|
9
6
|
- else
|
10
7
|
Please try again.
|
11
8
|
|
12
|
-
|
9
|
+
%p.text-center
|
10
|
+
= link_to 'Continue', root_path, class: 'btn btn-primary'
|
@@ -1,8 +1,5 @@
|
|
1
1
|
%h1.effective-heading= @page_title
|
2
2
|
|
3
|
-
%p.effective-orders-page-content
|
4
|
-
= link_to 'Home', root_path
|
5
|
-
|
6
3
|
%p.effective-orders-page-content
|
7
4
|
You have indicated that this order will be paid by #{@order.payment_provider}.
|
8
5
|
Your order will not be considered purchased until we receive your payment.
|
@@ -10,4 +7,5 @@
|
|
10
7
|
|
11
8
|
= render @order
|
12
9
|
|
13
|
-
|
10
|
+
%p.text-center
|
11
|
+
= link_to 'Continue', root_path, class: 'btn btn-primary'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
= javascript_include_tag(EffectiveOrders.moneris_checkout_script_url)
|
2
|
+
|
3
|
+
- moneris_checkout = moneris_checkout_preload_request(order)
|
4
|
+
|
5
|
+
.card
|
6
|
+
.card-body.bg-light
|
7
|
+
.mb-3.text-center
|
8
|
+
%h2 Checkout
|
9
|
+
|
10
|
+
= effective_form_with(scope: :moneris_checkout, url: effective_orders.moneris_checkout_order_path(order), data: { 'moneris-checkout-form': moneris_checkout.to_json }) do |f|
|
11
|
+
= f.hidden_field :purchased_url, value: purchased_url
|
12
|
+
= f.hidden_field :declined_url, value: declined_url
|
13
|
+
|
14
|
+
-# This is set by the moneris_checkout.js javascript
|
15
|
+
= f.hidden_field :ticket
|
16
|
+
|
17
|
+
= render('effective/orders/moneris_checkout/element')
|
18
|
+
|
19
|
+
.mt-3.text-center
|
20
|
+
%em
|
21
|
+
This checkout provided by
|
22
|
+
= succeed('.') do
|
23
|
+
= link_to('Moneris', 'https://www.moneris.com', target: '_blank', class: 'btn-link')
|
@@ -1,11 +1,9 @@
|
|
1
1
|
%h1.effective-heading= @page_title
|
2
2
|
|
3
|
-
%p.effective-orders-page-content
|
4
|
-
= link_to 'Home', root_path
|
5
|
-
|
6
3
|
%p.effective-orders-page-content
|
7
4
|
You have successfully purchased the following:
|
8
5
|
|
9
6
|
= render @order
|
10
7
|
|
11
|
-
|
8
|
+
%p.text-center
|
9
|
+
= link_to 'Continue', root_path, class: 'btn btn-primary'
|
@@ -1,10 +1,9 @@
|
|
1
1
|
%h1.effective-heading= @page_title
|
2
2
|
|
3
|
-
- if @order.user == current_user
|
3
|
+
- if !@order.purchased? && @order.user == current_user
|
4
4
|
= render_checkout(@order)
|
5
5
|
- else
|
6
|
-
= render
|
6
|
+
= render(@order)
|
7
7
|
|
8
|
-
%
|
9
|
-
|
10
|
-
= link_to 'Continue', effective_orders.orders_path, class: 'btn btn-primary'
|
8
|
+
%p.text-center
|
9
|
+
= link_to 'Continue', effective_orders.orders_path, class: 'btn btn-primary'
|
data/config/effective_orders.rb
CHANGED
@@ -166,6 +166,25 @@ EffectiveOrders.setup do |config|
|
|
166
166
|
# }
|
167
167
|
# end
|
168
168
|
|
169
|
+
# Moneris Checkout
|
170
|
+
config.moneris_checkout = false
|
171
|
+
|
172
|
+
# if Rails.env.production?
|
173
|
+
# config.moneris_checkout = {
|
174
|
+
# environment: 'prod',
|
175
|
+
# store_id: '',
|
176
|
+
# api_token: '',
|
177
|
+
# checkout_id: '',
|
178
|
+
# }
|
179
|
+
# else
|
180
|
+
# config.moneris_checkout = {
|
181
|
+
# environment: 'qa',
|
182
|
+
# store_id: 'store1',
|
183
|
+
# api_token: 'yesguy1',
|
184
|
+
# checkout_id: 'chktJF76Btore1',
|
185
|
+
# }
|
186
|
+
# end
|
187
|
+
|
169
188
|
# Paypal
|
170
189
|
config.paypal = false
|
171
190
|
|
data/config/routes.rb
CHANGED
@@ -16,8 +16,8 @@ module EffectiveOrders
|
|
16
16
|
eval File.read("#{config.root}/config/effective_orders.rb")
|
17
17
|
end
|
18
18
|
|
19
|
-
initializer
|
20
|
-
|
19
|
+
initializer 'effective_orders.assets' do |app|
|
20
|
+
app.config.assets.precompile += ['effective_orders_manifest.js', 'effective_orders/*']
|
21
21
|
end
|
22
22
|
|
23
23
|
initializer 'effective_orders.refund', after: :load_config_initializers do
|
data/lib/effective_orders.rb
CHANGED
@@ -34,7 +34,7 @@ module EffectiveOrders
|
|
34
34
|
# Features
|
35
35
|
:free_enabled, :mark_as_paid_enabled, :pretend_enabled, :pretend_message,
|
36
36
|
# Payment processors. false or Hash
|
37
|
-
:cheque, :moneris, :paypal, :phone, :refund, :stripe, :subscriptions, :trial
|
37
|
+
:cheque, :moneris, :moneris_checkout, :paypal, :phone, :refund, :stripe, :subscriptions, :trial
|
38
38
|
]
|
39
39
|
end
|
40
40
|
|
@@ -69,6 +69,10 @@ module EffectiveOrders
|
|
69
69
|
moneris.kind_of?(Hash)
|
70
70
|
end
|
71
71
|
|
72
|
+
def self.moneris_checkout?
|
73
|
+
moneris_checkout.kind_of?(Hash)
|
74
|
+
end
|
75
|
+
|
72
76
|
def self.paypal?
|
73
77
|
paypal.kind_of?(Hash)
|
74
78
|
end
|
@@ -98,7 +102,7 @@ module EffectiveOrders
|
|
98
102
|
end
|
99
103
|
|
100
104
|
def self.single_payment_processor?
|
101
|
-
[moneris?, paypal?, stripe?].select { |enabled| enabled }.length == 1
|
105
|
+
[moneris?, moneris_checkout?, paypal?, stripe?].select { |enabled| enabled }.length == 1
|
102
106
|
end
|
103
107
|
|
104
108
|
# The Effective::Order.payment_provider value must be in this collection
|
@@ -108,6 +112,7 @@ module EffectiveOrders
|
|
108
112
|
('credit card' if mark_as_paid?),
|
109
113
|
('free' if free?),
|
110
114
|
('moneris' if moneris?),
|
115
|
+
('moneris_checkout' if moneris_checkout?),
|
111
116
|
('paypal' if paypal?),
|
112
117
|
('phone' if phone?),
|
113
118
|
('pretend' if pretend?),
|
@@ -197,6 +202,22 @@ module EffectiveOrders
|
|
197
202
|
stripe_plans.map { |plan| [plan[:name], plan[:id]] }
|
198
203
|
end
|
199
204
|
|
205
|
+
def self.moneris_checkout_script_url
|
206
|
+
case EffectiveOrders.moneris_checkout.fetch(:environment)
|
207
|
+
when 'prod' then 'https://gateway.moneris.com/chkt/js/chkt_v1.00.js'
|
208
|
+
when 'qa' then 'https://gatewayt.moneris.com/chkt/js/chkt_v1.00.js'
|
209
|
+
else raise('unexpected EffectiveOrders.moneris_checkout :environment key. Please check your config/initializers/effective_orders.rb file')
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.moneris_request_url
|
214
|
+
case EffectiveOrders.moneris_checkout.fetch(:environment)
|
215
|
+
when 'prod' then 'https://gateway.moneris.com/chkt/request/request.php'
|
216
|
+
when 'qa' then 'https://gatewayt.moneris.com/chkt/request/request.php'
|
217
|
+
else raise('unexpected EffectiveOrders.moneris_checkout :environment key. Please check your config/initializers/effective_orders.rb file')
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
200
221
|
class SoldOutException < Exception; end
|
201
222
|
class AlreadyPurchasedException < Exception; end
|
202
223
|
end
|
@@ -61,6 +61,12 @@ class EffectiveOrdersMailerPreview < ActionMailer::Preview
|
|
61
61
|
order = Effective::Order.new(id: 1)
|
62
62
|
order.user = preview_user
|
63
63
|
preview_order_items.each { |atts| order.order_items.build(atts) }
|
64
|
+
|
65
|
+
order.state = 'purchased'
|
66
|
+
order.payment_card = 'visa'
|
67
|
+
order.purchased_at = Time.zone.now
|
68
|
+
order.payment = { 'f4l4' => '1234'}
|
69
|
+
|
64
70
|
order.valid?
|
65
71
|
order
|
66
72
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_orders
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: sassc
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: effective_addresses
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: '0'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: effective_bootstrap
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +108,62 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: sqlite3
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: devise
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: haml-rails
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: pry-byebug
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
111
167
|
description: Quickly build an online store with carts, orders, automatic email receipts
|
112
168
|
and payment collection via Stripe, StripeConnect, PayPal and Moneris.
|
113
169
|
email:
|
@@ -118,9 +174,12 @@ extra_rdoc_files: []
|
|
118
174
|
files:
|
119
175
|
- MIT-LICENSE
|
120
176
|
- README.md
|
177
|
+
- app/assets/config/effective_orders_manifest.js
|
178
|
+
- app/assets/images/effective_orders/logo.png
|
121
179
|
- app/assets/images/effective_orders/stripe.png
|
122
180
|
- app/assets/javascripts/effective_orders.js
|
123
181
|
- app/assets/javascripts/effective_orders/customers.js.coffee
|
182
|
+
- app/assets/javascripts/effective_orders/providers/moneris_checkout.js.coffee
|
124
183
|
- app/assets/javascripts/effective_orders/providers/stripe.js.coffee
|
125
184
|
- app/assets/javascripts/effective_orders/subscriptions.js.coffee
|
126
185
|
- app/assets/stylesheets/effective_orders.scss
|
@@ -137,6 +196,7 @@ files:
|
|
137
196
|
- app/controllers/effective/providers/free.rb
|
138
197
|
- app/controllers/effective/providers/mark_as_paid.rb
|
139
198
|
- app/controllers/effective/providers/moneris.rb
|
199
|
+
- app/controllers/effective/providers/moneris_checkout.rb
|
140
200
|
- app/controllers/effective/providers/paypal.rb
|
141
201
|
- app/controllers/effective/providers/phone.rb
|
142
202
|
- app/controllers/effective/providers/pretend.rb
|
@@ -148,6 +208,7 @@ files:
|
|
148
208
|
- app/datatables/admin/effective_orders_datatable.rb
|
149
209
|
- app/datatables/effective_orders_datatable.rb
|
150
210
|
- app/helpers/effective_carts_helper.rb
|
211
|
+
- app/helpers/effective_moneris_checkout_helper.rb
|
151
212
|
- app/helpers/effective_orders_helper.rb
|
152
213
|
- app/helpers/effective_paypal_helper.rb
|
153
214
|
- app/helpers/effective_stripe_helper.rb
|
@@ -213,6 +274,8 @@ files:
|
|
213
274
|
- app/views/effective/orders/index.html.haml
|
214
275
|
- app/views/effective/orders/mark_as_paid/_form.html.haml
|
215
276
|
- app/views/effective/orders/moneris/_form.html.haml
|
277
|
+
- app/views/effective/orders/moneris_checkout/_element.html.haml
|
278
|
+
- app/views/effective/orders/moneris_checkout/_form.html.haml
|
216
279
|
- app/views/effective/orders/new.html.haml
|
217
280
|
- app/views/effective/orders/paypal/_form.html.haml
|
218
281
|
- app/views/effective/orders/phone/_form.html.haml
|