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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +67 -1
  3. data/app/assets/config/effective_orders_manifest.js +3 -0
  4. data/app/assets/images/effective_orders/logo.png +0 -0
  5. data/app/assets/javascripts/effective_orders/providers/moneris_checkout.js.coffee +71 -0
  6. data/app/assets/javascripts/effective_orders.js +1 -1
  7. data/app/assets/stylesheets/effective_orders/_order.scss +4 -0
  8. data/app/controllers/effective/concerns/purchase.rb +3 -3
  9. data/app/controllers/effective/orders_controller.rb +1 -0
  10. data/app/controllers/effective/providers/moneris_checkout.rb +59 -0
  11. data/app/datatables/admin/effective_orders_datatable.rb +5 -8
  12. data/app/datatables/effective_orders_datatable.rb +3 -5
  13. data/app/helpers/effective_moneris_checkout_helper.rb +65 -0
  14. data/app/helpers/effective_orders_helper.rb +2 -19
  15. data/app/mailers/effective/orders_mailer.rb +6 -4
  16. data/app/models/concerns/acts_as_purchasable.rb +2 -0
  17. data/app/models/concerns/acts_as_subscribable.rb +1 -0
  18. data/app/models/concerns/acts_as_subscribable_buyer.rb +2 -1
  19. data/app/models/effective/order.rb +42 -11
  20. data/app/views/effective/orders/_checkout_step2.html.haml +3 -0
  21. data/app/views/effective/orders/_order.html.haml +1 -1
  22. data/app/views/effective/orders/_order_footer.html.haml +3 -1
  23. data/app/views/effective/orders/_order_header.html.haml +4 -20
  24. data/app/views/effective/orders/_order_payment.html.haml +7 -18
  25. data/app/views/effective/orders/declined.html.haml +2 -4
  26. data/app/views/effective/orders/deferred.html.haml +2 -4
  27. data/app/views/effective/orders/moneris_checkout/_element.html.haml +4 -0
  28. data/app/views/effective/orders/moneris_checkout/_form.html.haml +23 -0
  29. data/app/views/effective/orders/purchased.html.haml +2 -4
  30. data/app/views/effective/orders/show.html.haml +4 -5
  31. data/config/effective_orders.rb +19 -0
  32. data/config/routes.rb +1 -0
  33. data/lib/effective_orders/engine.rb +2 -2
  34. data/lib/effective_orders/version.rb +1 -1
  35. data/lib/effective_orders.rb +23 -2
  36. data/lib/generators/templates/effective_orders_mailer_preview.rb +6 -0
  37. metadata +69 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55f4ecfb00c2ff8fca1e88711877ca4c4a2c5e2772857645b1793eb42d672f6d
4
- data.tar.gz: 97d1e59387d065240d3b0c160f725831d808ea153d6aedce2104f277c769e005
3
+ metadata.gz: 78aa25d8f77169e21e2f05886c47479ac2f64d8de4657510b2723ab9d4246fbd
4
+ data.tar.gz: 22f9fd8d7747c3975952fe6edfc6e221fe567ec0b287e619ba3afd861dcc2bfb
5
5
  SHA512:
6
- metadata.gz: 74166e809d54fd9b2b0f4c266e59da9b0f8ff0947ac2166f6e88686fcaecf05a1c6e520933a935568717beae55a1db032aca72902641fbd031ecf60fe0302527
7
- data.tar.gz: 464f54b750a6feab8ec0ad9df11c1b8591aa70d33a58faaf0cb03eb03d584ea4362fc9247f3ad3425e3269585cb78a18529cfc28c1ae41eadc0a28d2304f1298
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
- ## Paying via Moneris
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
 
@@ -0,0 +1,3 @@
1
+ //= link_directory ../javascripts .js
2
+ //= link_directory ../stylesheets .css
3
+ //= link_directory ../images/effective_orders
@@ -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()
@@ -2,5 +2,5 @@
2
2
 
3
3
  //= require ./effective_orders/customers
4
4
  //= require ./effective_orders/subscriptions
5
- //= require_tree ./effective_orders/providers
6
5
 
6
+ //= require_tree ./effective_orders/providers
@@ -45,6 +45,10 @@ form.new_effective_order {
45
45
  a.remove_fields.dynamic { float: right; }
46
46
  }
47
47
 
48
+ .effective-moneris-checkout {
49
+ height: 640px;
50
+ }
51
+
48
52
  @media print {
49
53
  .effective-orders-page-content { display: none; }
50
54
 
@@ -18,7 +18,7 @@ module Effective
18
18
  end
19
19
  end
20
20
 
21
- purchased_url ||= effective_orders.purchased_order_path(':id')
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 ||= effective_orders.deferred_order_path(':id')
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 ||= effective_orders.declined_order_path(':id')
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
 
@@ -7,6 +7,7 @@ module Effective
7
7
  include Providers::Free
8
8
  include Providers::MarkAsPaid
9
9
  include Providers::Moneris
10
+ include Providers::MonerisCheckout
10
11
  include Providers::Paypal
11
12
  include Providers::Phone
12
13
  include Providers::Pretend
@@ -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
- if attributes[:user_id].blank? && attributes[:parent_id].blank?
18
- scope :purchased, default: true
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.includes(:addresses, :order_items, :user)
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
- scope = Effective::Order.all.where(user: user).includes(:addresses, :order_items, :user)
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
 
@@ -42,6 +42,8 @@ module ActsAsPurchasable
42
42
  end
43
43
 
44
44
  module ClassMethods
45
+ def acts_as_purchasable?; true; end
46
+
45
47
  def before_purchase(&block)
46
48
  send :define_method, :before_purchase do |order, order_item| self.instance_exec(order, order_item, &block) end
47
49
  end
@@ -40,6 +40,7 @@ module ActsAsSubscribable
40
40
  end
41
41
 
42
42
  module ClassMethods
43
+ def acts_as_subscribable?; true; end
43
44
  end
44
45
 
45
46
  def subscripter
@@ -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 ##{to_param}"
252
+ "Refund"
255
253
  elsif purchased?
256
- "Receipt ##{to_param}"
254
+ "Receipt"
257
255
  elsif pending?
258
- "Pending Order ##{to_param}"
256
+ "Pending Order"
259
257
  else
260
- "Order ##{to_param}"
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 +1,3 @@
1
- - # intentionally left blank
1
+ .effective-orders-footer
2
+ .mb-4.text-center
3
+ %p If you have any questions, please contact us or call right away.
@@ -1,23 +1,7 @@
1
1
  .effective-order-header
2
- %h2 Acme Industries Inc.
3
- .row
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
- .col-sm-6
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
- - if order.purchased?
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-details
2
+ .effective-order-payment
3
3
  %table.table
4
4
  %thead
5
5
  %tr
6
- %th Payment
7
- %th
6
+ %th Amount Paid
7
+ %th Date Paid
8
+ %th Payment Method
8
9
  %tbody
9
10
  %tr
10
- %td Provider
11
- %td= order.payment_provider
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
- = link_to 'Continue', root_path, class: 'btn btn-primary'
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
- = link_to 'Continue', root_path, class: 'btn btn-primary'
10
+ %p.text-center
11
+ = link_to 'Continue', root_path, class: 'btn btn-primary'
@@ -0,0 +1,4 @@
1
+ .effective-moneris-checkout
2
+ #moneris-checkout-error.text-center.alert-danger
3
+ #moneris-checkout-success.text-center
4
+ #monerisCheckout
@@ -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
- = link_to 'Continue', root_path, class: 'btn btn-primary'
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 @order
6
+ = render(@order)
7
7
 
8
- %hr
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'
@@ -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
@@ -10,6 +10,7 @@ EffectiveOrders::Engine.routes.draw do
10
10
  post :free
11
11
  post :mark_as_paid
12
12
  post :cheque
13
+ post :moneris_checkout
13
14
  post :phone
14
15
  post :pretend
15
16
  post :refund
@@ -16,8 +16,8 @@ module EffectiveOrders
16
16
  eval File.read("#{config.root}/config/effective_orders.rb")
17
17
  end
18
18
 
19
- initializer "effective_orders.append_precompiled_assets" do |app|
20
- Rails.application.config.assets.precompile += ['effective_orders/*']
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
@@ -1,3 +1,3 @@
1
1
  module EffectiveOrders
2
- VERSION = '5.0.3'.freeze
2
+ VERSION = '5.1.1'.freeze
3
3
  end
@@ -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.0.3
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-03-23 00:00:00.000000000 Z
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: devise
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: sass
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: 4.0.0
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: 4.0.0
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