effective_orders 5.0.3 → 5.1.1

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.
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