effective_orders 5.0.1 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) 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.js +1 -1
  6. data/app/assets/javascripts/effective_orders/providers/moneris_checkout.js.coffee +71 -0
  7. data/app/assets/stylesheets/effective_orders/_order.scss +4 -0
  8. data/app/controllers/effective/concerns/purchase.rb +14 -21
  9. data/app/controllers/effective/orders_controller.rb +2 -2
  10. data/app/controllers/effective/providers/free.rb +0 -1
  11. data/app/controllers/effective/providers/mark_as_paid.rb +1 -2
  12. data/app/controllers/effective/providers/moneris_checkout.rb +59 -0
  13. data/app/controllers/effective/providers/pretend.rb +1 -2
  14. data/app/controllers/effective/providers/refund.rb +1 -2
  15. data/app/controllers/effective/providers/stripe.rb +1 -2
  16. data/app/datatables/admin/effective_orders_datatable.rb +5 -8
  17. data/app/datatables/effective_orders_datatable.rb +3 -7
  18. data/app/helpers/effective_moneris_checkout_helper.rb +65 -0
  19. data/app/helpers/effective_orders_helper.rb +3 -26
  20. data/app/mailers/effective/orders_mailer.rb +6 -4
  21. data/app/models/concerns/acts_as_purchasable.rb +2 -0
  22. data/app/models/concerns/acts_as_subscribable.rb +1 -0
  23. data/app/models/concerns/acts_as_subscribable_buyer.rb +2 -1
  24. data/app/models/effective/order.rb +56 -35
  25. data/app/models/effective/order_item.rb +10 -0
  26. data/app/models/effective/product.rb +2 -0
  27. data/app/views/effective/orders/_checkout_step2.html.haml +3 -0
  28. data/app/views/effective/orders/_order.html.haml +1 -1
  29. data/app/views/effective/orders/_order_actions.html.haml +1 -1
  30. data/app/views/effective/orders/_order_footer.html.haml +3 -1
  31. data/app/views/effective/orders/_order_header.html.haml +4 -20
  32. data/app/views/effective/orders/_order_payment.html.haml +7 -18
  33. data/app/views/effective/orders/declined.html.haml +2 -4
  34. data/app/views/effective/orders/deferred.html.haml +2 -4
  35. data/app/views/effective/orders/moneris_checkout/_element.html.haml +4 -0
  36. data/app/views/effective/orders/moneris_checkout/_form.html.haml +23 -0
  37. data/app/views/effective/orders/purchased.html.haml +2 -4
  38. data/app/views/effective/orders/show.html.haml +5 -2
  39. data/config/effective_orders.rb +19 -0
  40. data/config/routes.rb +1 -0
  41. data/lib/effective_orders.rb +23 -2
  42. data/lib/effective_orders/engine.rb +2 -2
  43. data/lib/effective_orders/version.rb +1 -1
  44. data/lib/generators/templates/effective_orders_mailer_preview.rb +6 -0
  45. metadata +69 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72eca7d0655eb6a817f703d2787d7a211d5b9da7889aaf1920ec79edb49384b7
4
- data.tar.gz: ff602f25ce5ab9294c292e98060d505da015b6fb38c57f11463705d404871183
3
+ metadata.gz: 31540d5d07a5c2afc891284cd037d88d25ea6aba9db57073a53b5dd60c952a11
4
+ data.tar.gz: 502ad51ce45452ff307292de9d2f16c934a7e1a0aca7c62376272b1f3ede07b0
5
5
  SHA512:
6
- metadata.gz: 251acbaf892b9f51e0fd6ebd739d1a64538b6a597f071afcd4d2c0fd3b4b839c9f4423594620ae31ed7ce4dc8c92a79bbe30e7d6f2d07a3ab29607eab04accbe
7
- data.tar.gz: bd8a5fd153eba267e138a32f598e01888c427fde5171327cc6271b8a1d7dcea7931f2d4b3187981f7bcea1e3e397cef4aafedd00aa64504c66b221f0deadd04b
6
+ metadata.gz: 7541296d5ee6f6d52dc2edf94938f28734bf8da046612c46b0de23ee51fcd70c2eb80a32dd53534d16ffd3a9de72a923de9fffa709c4b96651ccf49fe7779b9b
7
+ data.tar.gz: 7be888605850e6dda6b952bf6ba9cceb575577b3d18ded8c118c8028890715bf41c8d8ded387de1bd5378c38207329af61709d071f2a80eec528ce6c7e701164
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
@@ -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
@@ -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()
@@ -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
 
@@ -5,28 +5,21 @@ module Effective
5
5
 
6
6
  protected
7
7
 
8
- def order_purchased(payment:, provider:, card: 'none', email: true, skip_buyer_validations: false, purchased_url: nil, declined_url: nil)
9
- begin
10
- @order.purchase!(payment: payment, provider: provider, card: card, email: email, skip_buyer_validations: skip_buyer_validations)
11
-
12
- Effective::Cart.where(user: @order.user).destroy_all
13
-
14
- if flash[:success].blank?
15
- if EffectiveOrders.mailer[:send_order_receipt_to_buyer] && email
16
- flash[:success] = "Payment successful! A receipt has been sent to #{@order.emails_send_to}"
17
- else
18
- flash[:success] = "Payment successful! An email receipt has not been sent."
19
- end
20
- end
8
+ def order_purchased(payment:, provider:, card: 'none', email: true, skip_buyer_validations: false, purchased_url: nil)
9
+ @order.purchase!(payment: payment, provider: provider, card: card, email: email, skip_buyer_validations: skip_buyer_validations)
21
10
 
22
- purchased_url ||= effective_orders.purchased_order_path(':id')
23
- redirect_to purchased_url.gsub(':id', @order.to_param.to_s)
24
- rescue => e
25
- flash[:danger] = "An error occurred while processing your payment: #{e.message}. Please try again."
11
+ Effective::Cart.where(user: @order.user).destroy_all
26
12
 
27
- declined_url ||= effective_orders.declined_order_path(':id')
28
- redirect_to declined_url.gsub(':id', @order.to_param.to_s)
13
+ if flash[:success].blank?
14
+ if email && EffectiveOrders.mailer[:send_order_receipt_to_buyer]
15
+ flash[:success] = "Payment successful! A receipt has been sent to #{@order.emails_send_to}"
16
+ else
17
+ flash[:success] = "Payment successful! An email receipt has not been sent."
18
+ end
29
19
  end
20
+
21
+ purchased_url = effective_orders.purchased_order_path(':id') if purchased_url.blank?
22
+ redirect_to purchased_url.gsub(':id', @order.to_param.to_s)
30
23
  end
31
24
 
32
25
  def order_deferred(provider:, email: true, deferred_url: nil)
@@ -42,7 +35,7 @@ module Effective
42
35
  end
43
36
  end
44
37
 
45
- deferred_url ||= effective_orders.deferred_order_path(':id')
38
+ deferred_url = effective_orders.deferred_order_path(':id') if deferred_url.blank?
46
39
  redirect_to deferred_url.gsub(':id', @order.to_param.to_s)
47
40
  end
48
41
 
@@ -53,7 +46,7 @@ module Effective
53
46
  flash[:danger] = 'Payment was unsuccessful. Your credit card was declined by the payment processor. Please try again.'
54
47
  end
55
48
 
56
- declined_url ||= effective_orders.declined_order_path(':id')
49
+ declined_url = effective_orders.declined_order_path(':id') if declined_url.blank?
57
50
  redirect_to declined_url.gsub(':id', @order.to_param.to_s)
58
51
  end
59
52
 
@@ -1,19 +1,19 @@
1
1
  module Effective
2
2
  class OrdersController < ApplicationController
3
+ include Effective::CrudController
3
4
  include Concerns::Purchase
4
5
 
5
6
  include Providers::Cheque
6
7
  include Providers::Free
7
8
  include Providers::MarkAsPaid
8
9
  include Providers::Moneris
10
+ include Providers::MonerisCheckout
9
11
  include Providers::Paypal
10
12
  include Providers::Phone
11
13
  include Providers::Pretend
12
14
  include Providers::Refund
13
15
  include Providers::Stripe
14
16
 
15
- include Effective::CrudController
16
-
17
17
  if (config = EffectiveOrders.layout)
18
18
  layout(config.kind_of?(Hash) ? (config[:orders] || config[:application]) : config)
19
19
  end
@@ -21,7 +21,6 @@ module Effective
21
21
  provider: 'free',
22
22
  card: 'none',
23
23
  purchased_url: free_params[:purchased_url],
24
- declined_url: free_params[:declined_url],
25
24
  email: false
26
25
  )
27
26
  end
@@ -19,8 +19,7 @@ module Effective
19
19
  card: mark_as_paid_params[:payment_card],
20
20
  email: @order.send_mark_as_paid_email_to_buyer?,
21
21
  skip_buyer_validations: true,
22
- purchased_url: effective_orders.admin_order_path(@order),
23
- declined_url: effective_orders.admin_order_path(@order)
22
+ purchased_url: effective_orders.admin_order_path(@order)
24
23
  )
25
24
  end
26
25
 
@@ -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,8 +14,7 @@ module Effective
14
14
  payment: 'for pretend',
15
15
  provider: 'pretend',
16
16
  card: 'none',
17
- purchased_url: pretend_params[:purchased_url],
18
- declined_url: pretend_params[:declined_url]
17
+ purchased_url: pretend_params[:purchased_url]
19
18
  )
20
19
  end
21
20
 
@@ -21,8 +21,7 @@ module Effective
21
21
  order_purchased(
22
22
  payment: 'refund. no payment required.',
23
23
  provider: 'refund',
24
- purchased_url: refund_params[:purchased_url],
25
- declined_url: refund_params[:declined_url]
24
+ purchased_url: refund_params[:purchased_url]
26
25
  )
27
26
  end
28
27
 
@@ -26,8 +26,7 @@ module Effective
26
26
  payment: payment,
27
27
  provider: 'stripe',
28
28
  card: payment[:card],
29
- purchased_url: stripe_params[:purchased_url],
30
- declined_url: stripe_params[:declined_url]
29
+ purchased_url: stripe_params[:purchased_url]
31
30
  )
32
31
  end
33
32
 
@@ -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
@@ -6,8 +6,6 @@ class EffectiveOrdersDatatable < Effective::Datatable
6
6
  scope :purchased, default: true
7
7
  scope :deferred
8
8
  scope :refunds
9
- scope :not_purchased
10
- scope :all
11
9
  end
12
10
  end
13
11
 
@@ -61,7 +59,9 @@ class EffectiveOrdersDatatable < Effective::Datatable
61
59
  end
62
60
 
63
61
  collection do
64
- 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)
65
65
 
66
66
  if EffectiveOrders.orders_collection_scope.respond_to?(:call)
67
67
  scope = EffectiveOrders.orders_collection_scope.call(scope)
@@ -78,8 +78,4 @@ class EffectiveOrdersDatatable < Effective::Datatable
78
78
  scope
79
79
  end
80
80
 
81
- def user
82
- @user ||= current_user.class.find(attributes[:user_id])
83
- end
84
-
85
81
  end