workarea-kount 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +20 -0
  3. data/.eslintrc +24 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  5. data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  6. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  7. data/.github/workflows/ci.yml +58 -0
  8. data/.gitignore +14 -0
  9. data/.rubocop.yml +2 -0
  10. data/CHANGELOG.md +212 -0
  11. data/CODE_OF_CONDUCT.md +3 -0
  12. data/CONTRIBUTING.md +3 -0
  13. data/Gemfile +17 -0
  14. data/LICENSE.md +3 -0
  15. data/README.md +98 -0
  16. data/Rakefile +53 -0
  17. data/app/controllers/workarea/admin/orders_controller.decorator +5 -0
  18. data/app/controllers/workarea/storefront/checkout/place_order_controller.decorator +11 -0
  19. data/app/controllers/workarea/storefront/kount_controller.rb +19 -0
  20. data/app/controllers/workarea/storefront/kount_orders_controller.rb +40 -0
  21. data/app/lib/active_shipping/rate_estimate.decorator +10 -0
  22. data/app/mailers/workarea/storefront/order_mailer.decorator +14 -0
  23. data/app/models/workarea/checkout.decorator +37 -0
  24. data/app/models/workarea/checkout/fraud/kount_analyzer.rb +71 -0
  25. data/app/models/workarea/kount/ens_event.rb +13 -0
  26. data/app/models/workarea/kount/order.rb +14 -0
  27. data/app/models/workarea/order.decorator +62 -0
  28. data/app/models/workarea/order/fraud_decision.decorator +9 -0
  29. data/app/models/workarea/order/item.decorator +8 -0
  30. data/app/models/workarea/order/status/review.rb +13 -0
  31. data/app/models/workarea/payment/credit_card.decorator +13 -0
  32. data/app/models/workarea/payment/payment.decorator +11 -0
  33. data/app/models/workarea/payment/status/kount_declined.rb +13 -0
  34. data/app/models/workarea/payment/status/kount_review.rb +13 -0
  35. data/app/models/workarea/payment/tender/credit_card.decorator +10 -0
  36. data/app/models/workarea/search/admin.decorator +12 -0
  37. data/app/models/workarea/search/admin/order.decorator +7 -0
  38. data/app/models/workarea/shipping/rate_lookup.decorator +26 -0
  39. data/app/models/workarea/shipping/service.decorator +9 -0
  40. data/app/models/workarea/shipping/service_selection.decorator +7 -0
  41. data/app/models/workarea/shipping_option.decorator +27 -0
  42. data/app/services/workarea/kount/cancel_order_under_review.rb +28 -0
  43. data/app/services/workarea/kount/event.rb +43 -0
  44. data/app/services/workarea/kount/event/dmc_event.rb +9 -0
  45. data/app/services/workarea/kount/event/risk_change_event.rb +21 -0
  46. data/app/services/workarea/kount/event/special_alert_event.rb +21 -0
  47. data/app/services/workarea/kount/event/workflow_event.rb +25 -0
  48. data/app/services/workarea/kount/event_batch.rb +37 -0
  49. data/app/services/workarea/kount/order_fraud_update_service.rb +42 -0
  50. data/app/services/workarea/kount/ris_inquiry.rb +120 -0
  51. data/app/services/workarea/kount/ris_inquiry/product.rb +53 -0
  52. data/app/services/workarea/kount/ris_request.rb +84 -0
  53. data/app/services/workarea/kount/ris_update.rb +39 -0
  54. data/app/view_models/workarea/admin/order_view_model.decorator +35 -0
  55. data/app/view_models/workarea/storefront/order_view_model.decorator +11 -0
  56. data/app/views/workarea/admin/orders/_kount.html.haml +28 -0
  57. data/app/views/workarea/admin/orders/kount.html.haml +46 -0
  58. data/app/views/workarea/storefront/checkouts/_kount_data_collector.html.haml +4 -0
  59. data/app/views/workarea/storefront/order_mailer/hold_denial.html.haml +14 -0
  60. data/app/workers/workarea/kount/process_review_order.rb +75 -0
  61. data/app/workers/workarea/kount/update_ris_inquiry.rb +31 -0
  62. data/bin/rails +18 -0
  63. data/config/initializers/appends.rb +11 -0
  64. data/config/initializers/workarea.rb +26 -0
  65. data/config/locales/en.yml +26 -0
  66. data/config/routes.rb +14 -0
  67. data/doc/Kount Technical Specification Guide 5.5.5.pdf +0 -0
  68. data/lib/workarea/kount.rb +87 -0
  69. data/lib/workarea/kount/address.rb +39 -0
  70. data/lib/workarea/kount/bogus_gateway.rb +415 -0
  71. data/lib/workarea/kount/engine.rb +8 -0
  72. data/lib/workarea/kount/errors.rb +2 -0
  73. data/lib/workarea/kount/gateway.rb +50 -0
  74. data/lib/workarea/kount/mappings.rb +195 -0
  75. data/lib/workarea/kount/payment_types.rb +50 -0
  76. data/lib/workarea/kount/response.rb +141 -0
  77. data/lib/workarea/kount/security_mash.rb +79 -0
  78. data/lib/workarea/kount/user_defined_fields.rb +16 -0
  79. data/lib/workarea/kount/version.rb +5 -0
  80. data/lib/workarea/mailer_previews/storefront/order_mailer_preview.rb +10 -0
  81. data/test/dummy/Rakefile +6 -0
  82. data/test/dummy/app/assets/config/manifest.js +4 -0
  83. data/test/dummy/app/assets/images/.keep +0 -0
  84. data/test/dummy/app/assets/javascripts/application.js +13 -0
  85. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  86. data/test/dummy/app/controllers/application_controller.rb +3 -0
  87. data/test/dummy/app/controllers/concerns/.keep +0 -0
  88. data/test/dummy/app/helpers/application_helper.rb +2 -0
  89. data/test/dummy/app/jobs/application_job.rb +2 -0
  90. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  91. data/test/dummy/app/models/concerns/.keep +0 -0
  92. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  93. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  94. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  95. data/test/dummy/bin/bundle +3 -0
  96. data/test/dummy/bin/rails +4 -0
  97. data/test/dummy/bin/rake +4 -0
  98. data/test/dummy/bin/setup +34 -0
  99. data/test/dummy/bin/update +29 -0
  100. data/test/dummy/config.ru +5 -0
  101. data/test/dummy/config/application.rb +23 -0
  102. data/test/dummy/config/boot.rb +5 -0
  103. data/test/dummy/config/cable.yml +9 -0
  104. data/test/dummy/config/environment.rb +5 -0
  105. data/test/dummy/config/environments/development.rb +56 -0
  106. data/test/dummy/config/environments/production.rb +86 -0
  107. data/test/dummy/config/environments/test.rb +44 -0
  108. data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
  109. data/test/dummy/config/initializers/assets.rb +11 -0
  110. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  111. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  112. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  113. data/test/dummy/config/initializers/inflections.rb +16 -0
  114. data/test/dummy/config/initializers/mime_types.rb +4 -0
  115. data/test/dummy/config/initializers/new_framework_defaults.rb +21 -0
  116. data/test/dummy/config/initializers/session_store.rb +3 -0
  117. data/test/dummy/config/initializers/workarea.rb +5 -0
  118. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  119. data/test/dummy/config/locales/en.yml +23 -0
  120. data/test/dummy/config/puma.rb +47 -0
  121. data/test/dummy/config/routes.rb +6 -0
  122. data/test/dummy/config/secrets.yml +22 -0
  123. data/test/dummy/config/spring.rb +6 -0
  124. data/test/dummy/db/seeds.rb +2 -0
  125. data/test/dummy/lib/assets/.keep +0 -0
  126. data/test/dummy/log/.keep +0 -0
  127. data/test/dummy/public/404.html +67 -0
  128. data/test/dummy/public/422.html +67 -0
  129. data/test/dummy/public/500.html +66 -0
  130. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  131. data/test/dummy/public/apple-touch-icon.png +0 -0
  132. data/test/dummy/public/favicon.ico +0 -0
  133. data/test/factories/kount.rb +164 -0
  134. data/test/integration/workarea/api/admin/payment_transactions_integration_test.decorator +29 -0
  135. data/test/integration/workarea/kount_moneris_integration_test.rb +37 -0
  136. data/test/integration/workarea/storefront/kount_integration_test.rb +37 -0
  137. data/test/integration/workarea/storefront/kount_orders_integration_test.rb +89 -0
  138. data/test/lib/workarea/kount/response_test.rb +95 -0
  139. data/test/lib/workarea/kount/security_mash_test.rb +62 -0
  140. data/test/models/workarea/checkout/fraud/kount_analyzer_test.rb +44 -0
  141. data/test/models/workarea/checkout_test.decorator +22 -0
  142. data/test/models/workarea/order/queries_test.decorator +28 -0
  143. data/test/models/workarea/order_test.decorator +25 -0
  144. data/test/models/workarea/payment/payment_test.rb +106 -0
  145. data/test/models/workarea/payment/saved_credit_card_test.rb +24 -0
  146. data/test/models/workarea/payment_test.decorator +54 -0
  147. data/test/models/workarea/shipping_option_test.rb +29 -0
  148. data/test/services/workarea/kount/event_batch_test.rb +95 -0
  149. data/test/services/workarea/kount/event_test.rb +51 -0
  150. data/test/services/workarea/kount/order_fraud_update_service_test.rb +48 -0
  151. data/test/support/workarea/kount_api_config.rb +27 -0
  152. data/test/system/workarea/kount_system_test.rb +72 -0
  153. data/test/system/workarea/storefront/kount_guest_checkout_system_test.rb +32 -0
  154. data/test/system/workarea/storefront/kount_logged_in_checkout_system_test.rb +102 -0
  155. data/test/test_helper.rb +16 -0
  156. data/test/vcr_cassettes/kount/basic_fraud_test.yml +43 -0
  157. data/test/vcr_cassettes/kount/integration/moneris_new_credit_card.yml +84 -0
  158. data/test/vcr_cassettes/kount/integration/moneris_saved_credit_card.yml +84 -0
  159. data/test/vcr_cassettes/kount/order_fraud_update.yml +82 -0
  160. data/test/workers/workarea/kount/clean_orders_test.rb +40 -0
  161. data/test/workers/workarea/kount/process_review_order_test.rb +100 -0
  162. data/workarea-kount.gemspec +17 -0
  163. metadata +238 -0
@@ -0,0 +1,3 @@
1
+ View this plugin's license here:
2
+
3
+ <https://github.com/workarea-commerce/workarea/blob/master/LICENSE.md>
@@ -0,0 +1,98 @@
1
+ # Workarea Kount
2
+
3
+ Kount plugin for the Workarea platform.
4
+
5
+ ## Kount Response Codes
6
+
7
+ Kount's Risk Inquiry Services will return one of three values.
8
+
9
+ Approved - the order is not suspected as fraud
10
+
11
+ Decline - the order is fraud
12
+
13
+ Hold for manager review - the order is suspected fraud
14
+
15
+ ## Kount Order Flow
16
+
17
+ ### In Checkout
18
+
19
+ The Kount plugin sends the credit card and paypal orders to Kount before payment
20
+ is captured. Based on the response from Kount different actions will be taken.
21
+
22
+ #### Approved - The order is not fraud
23
+
24
+ The order is placed.
25
+
26
+ #### Decline - The order is fraud
27
+
28
+ An error is shown to the customer and redirected back to the payment step.
29
+
30
+ #### Hold for manager review - the order is suspected fraud
31
+
32
+ The credit card is tokenized and inventory is captured but the payment is not
33
+ authorized/purchased. The customer is shown the order confirmation as if the
34
+ order is placed. A Kount admin user needs to use approve or decline the order
35
+ via the Kount admin.
36
+
37
+ The Kount Event Notificaion System (ENS) will post the data back to Workarea.
38
+
39
+ If the admin declines the order in Kount, the order is canceled and the customer
40
+ recieves a cancelation email.
41
+
42
+ If the admin approves the order, the payment is attemped to be captured. If the
43
+ payment captures successfully the order is placed. If the payment fails
44
+ authorization/purchase, the order is canceled and the customer recives a
45
+ cancelation email.
46
+
47
+ ## Configuration
48
+
49
+ Add values for `merchant_id`, `version`, `key`, and `ksalt` to your application secrets
50
+
51
+ ```yaml
52
+ kount:
53
+ merchant_id:
54
+ version:
55
+ key:
56
+ ksalt:
57
+ ens_username: username for basic auth for ENS
58
+ ens_password: password for basic auth for ENS
59
+ kount_site: <site name for ENS>
60
+ ```
61
+
62
+ ### Event Notification System Configuration
63
+
64
+ The Kount ENS requires configuration in Workarea to match configuration in Kount.
65
+ If the ENS is not configured properly, Kount review decisions will not be
66
+ received by Workarea.
67
+
68
+ Workarea uses basic auth credentials `ens_username:ens_password` to authenticate
69
+ requests from the Kount ENS. If your application is behind basic_auth (e.g. in
70
+ staging or QA) you should configure these credentials to match your basic auth
71
+ credentials for the environment. If your application is not behind basic auth
72
+ these credentials can be anything you want, as long as they are secure.
73
+
74
+ #### Kount Site
75
+
76
+ The `kount_site` configuration is used by kount ENS to determine which endpoint
77
+ events should be sent to. If no `kount_site` is provided the DEFAULT site will
78
+ be used. `kount_site` can be used to configure different ENS endpoints for
79
+ testing inQA and Staging, or for multi-site implementations.
80
+
81
+ #### Configure ENS in Kount
82
+
83
+ In the Kount admin navigate to: Fraud Control -> Websites -> Add Website
84
+
85
+ The ENS Api URL should look like `https://ENS_USERNAME:ENS_PASSWORD@WEBSITE_DOMAIN/kount_orders`
86
+
87
+ Example: `https://kount:aksjei8243d8@www.example.com/kount_orders`
88
+
89
+ ## Workarea Platform Documentation
90
+
91
+ See [http://developer.workarea.com](http://developer.workarea.com) for Workarea
92
+ platform documentation.
93
+
94
+ ## Copyright & Licensing
95
+
96
+ Copyright WebLinc 2018. All rights reserved.
97
+
98
+ For licensing, contact sales@weblinc.com.
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ require 'rdoc/task'
9
+
10
+ RDoc::Task.new(:rdoc) do |rdoc|
11
+ rdoc.rdoc_dir = 'rdoc'
12
+ rdoc.title = 'Tasker'
13
+ rdoc.options << '--line-numbers'
14
+ rdoc.rdoc_files.include('README.md')
15
+ rdoc.rdoc_files.include('lib/**/*.rb')
16
+ end
17
+
18
+ APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
19
+ load 'rails/tasks/engine.rake'
20
+ load 'rails/tasks/statistics.rake'
21
+ load 'workarea/changelog.rake'
22
+
23
+ require 'rake/testtask'
24
+
25
+ Rake::TestTask.new(:test) do |t|
26
+ t.libs << 'lib'
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
33
+
34
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
35
+ require 'workarea/kount/version'
36
+
37
+ desc "Release version #{Workarea::Kount::VERSION} of the gem"
38
+ task :release do
39
+ host = "https://#{ENV['BUNDLE_GEMS__WORKAREA__COM']}@gems.workarea.com"
40
+
41
+ Rake::Task['workarea:changelog'].execute
42
+ system 'git add CHANGELOG.md'
43
+ system 'git commit -m "Update CHANGELOG"'
44
+ system 'git push origin HEAD'
45
+
46
+ system "git tag -a v#{Workarea::Kount::VERSION} -m 'Tagging #{Workarea::Kount::VERSION}'"
47
+ system 'git push --tags'
48
+
49
+ system 'gem build workarea-kount.gemspec'
50
+ system "gem push workarea-kount-#{Workarea::Kount::VERSION}.gem"
51
+ system "gem push workarea-kount-#{Workarea::Kount::VERSION}.gem --host #{host}"
52
+ system "rm workarea-kount-#{Workarea::Kount::VERSION}.gem"
53
+ end
@@ -0,0 +1,5 @@
1
+ module Workarea
2
+ decorate Admin::OrdersController, with: :kount do
3
+ def kount; end
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module Workarea
2
+ decorate Storefront::Checkout::PlaceOrderController, with: :kount do
3
+ def try_place_order
4
+ if current_checkout.place_order || current_checkout.handle_kount_review
5
+ completed_place_order
6
+ else
7
+ incomplete_place_order
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ module Workarea
2
+ module Storefront
3
+ class KountController < Workarea::Storefront::ApplicationController
4
+ def data_collector
5
+ current_order.update_attributes(kount_session_id: kount_session_id)
6
+
7
+ params = { merchant_id: Workarea::Kount.merchant_id, s: kount_session_id }
8
+
9
+ redirect_to "#{Workarea::Kount.data_collector_url}logo.htm?#{params.to_query}", status: 302
10
+ end
11
+
12
+ private
13
+
14
+ def kount_session_id
15
+ @kount_session_id ||= "#{current_order.id}#{Time.now.to_i}R#{rand(10000..99999)}"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,40 @@
1
+ module Workarea
2
+ module Storefront
3
+ class KountOrdersController < ApplicationController
4
+ skip_before_action :verify_authenticity_token, only: [:bulk]
5
+ before_action :authenticate
6
+
7
+ def bulk
8
+ event_batch = Kount::EventBatch.new(request.raw_post)
9
+
10
+ if event_batch.valid?
11
+ event_batch.process!
12
+ successful_response
13
+ else
14
+ unsuccessful_response
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def authenticate
21
+ authenticated = authenticate_with_http_basic do |username, password|
22
+ Kount.credentials[:ens_username].present? &&
23
+ Kount.credentials[:ens_password].present? &&
24
+ username == Kount.credentials[:ens_username] &&
25
+ password == Kount.credentials[:ens_password]
26
+ end
27
+
28
+ unsuccessful_response unless authenticated
29
+ end
30
+
31
+ def successful_response
32
+ render json: { status: 200 }
33
+ end
34
+
35
+ def unsuccessful_response
36
+ head :bad_request
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,10 @@
1
+ module ActiveShipping
2
+ decorate RateEstimate, with: :kount do
3
+ decorated { attr_accessor :kount_code }
4
+
5
+ def initialize(origin, destination, carrier, service_name, options = {})
6
+ super
7
+ self.kount_code = options[:kount_code]
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ module Workarea
2
+ decorate Storefront::OrderMailer, with: :kount do
3
+ def hold_denial(order_id)
4
+ order = Order.find(order_id)
5
+ @order = Storefront::OrderViewModel.new(order)
6
+ @recommendations = Storefront::EmailRecommendationsViewModel.wrap(order)
7
+
8
+ mail(
9
+ to: @order.email,
10
+ subject: t('workarea.storefront.email.hold_denial.subject', order_id: @order.id)
11
+ )
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,37 @@
1
+ module Workarea
2
+ decorate Checkout, with: :kount do
3
+ def handle_kount_review
4
+ return false unless order.under_review?
5
+ return false unless complete?
6
+ return false unless shippable?
7
+ return false unless payable?
8
+
9
+ inventory.purchase
10
+ return false unless inventory.captured?
11
+
12
+ return true unless payment.uses_credit_card?
13
+ store_credit_card
14
+ end
15
+
16
+ def handle_kount_approved
17
+ unless payment_collection.purchase
18
+ captured_inventory&.rollback
19
+ return false
20
+ end
21
+
22
+ result = order.place
23
+ place_order_side_effects if result
24
+ result
25
+ end
26
+
27
+ private
28
+
29
+ def captured_inventory
30
+ @captured_inventory ||= Inventory::Transaction.captured_for_order(order.id)
31
+ end
32
+
33
+ def store_credit_card
34
+ Payment::StoreCreditCard.new(payment.credit_card).save!
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Workarea
4
+ class Checkout
5
+ module Fraud
6
+ class KountAnalyzer < Analyzer
7
+ # This is the `:mode` value used in the RIS Inquiry request to
8
+ # Kount. It tells Kount that this is a new order, and not an
9
+ # update to an existing order as used in the updater service
10
+ # class.
11
+ #
12
+ # @return [String]
13
+ MODE_Q = 'Q'
14
+
15
+ delegate :gateway, to: Workarea::Kount
16
+ delegate :kount_mode, :kount_request_user_defined_fields, to: :checkout
17
+ delegate :decision, to: :kount_response
18
+
19
+ # Tell Kount about the order and record its response.
20
+ #
21
+ # @return [Workarea::Order::FraudDecision]
22
+ def make_decision
23
+ kount_order.update_attributes!(response: kount_response)
24
+
25
+ Workarea::Order::FraudDecision.new(
26
+ decision: decision,
27
+ message: message
28
+ )
29
+ end
30
+
31
+ # Data for this Order from Kount.
32
+ #
33
+ # @return [Workarea::Kount::Order]
34
+ def kount_order
35
+ @kount_order ||= Workarea::Kount::Order.find_or_initialize_by(id: order.id)
36
+ end
37
+
38
+ private
39
+
40
+ # Build the RIS inquiry request.
41
+ #
42
+ # @private
43
+ # @return [Hash]
44
+ def inquiry
45
+ Workarea::Kount::RisInquiry.new(
46
+ order: order,
47
+ payment: payment,
48
+ shippings: shippings,
49
+ mode: MODE_Q
50
+ ).to_h
51
+ end
52
+
53
+ # Response for the Kount RIS inquiry request.
54
+ #
55
+ # @private
56
+ # @return [Workarea::Kount::Response]
57
+ def kount_response
58
+ @kount_response ||= gateway.call(inquiry)
59
+ end
60
+
61
+ # Translated message for the Kount decision.
62
+ #
63
+ # @private
64
+ # @return [String]
65
+ def message
66
+ I18n.t(decision, scope: 'workarea.storefront.fraud.kount')
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,13 @@
1
+ module Workarea
2
+ module Kount
3
+ class EnsEvent
4
+ include ApplicationDocument
5
+
6
+ field :xml, type: String
7
+
8
+ embedded_in :kount_order,
9
+ class_name: 'Workarea::Kount::Order',
10
+ inverse_of: :ens_events
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module Workarea
2
+ module Kount
3
+ class Order
4
+ include ApplicationDocument
5
+
6
+ field :response, type: Workarea::Kount::Response
7
+ field :update_response, type: Workarea::Kount::Response
8
+
9
+ embeds_many :ens_events, class_name: 'Workarea::Kount::EnsEvent'
10
+
11
+ index(created_at: -1)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,62 @@
1
+ module Workarea
2
+ decorate Order, with: :kount do
3
+ decorated do
4
+ field :kount_session_id, type: String
5
+ field :kount_decision, type: Symbol
6
+
7
+ scope :not_under_review, -> { where(:kount_decision.ne => :review) }
8
+
9
+ before_save :set_kount_decision, if: :fraud_decision?
10
+ end
11
+
12
+ class_methods do
13
+ # Query for orders which have expired in checkout, meaning they have been
14
+ # not been placed or updated for longer than the
15
+ # +Workarea.config.order_expiration_period+, but have started
16
+ # checkout. Contrast this with +Order.expired+, which does not
17
+ # factor in orders that have started checkout.
18
+ #
19
+ # Doesn't include orders under review or declined by kount
20
+ #
21
+ # @return [Mongoid::Criteria]
22
+ def expired_in_checkout
23
+ super.nin(kount_decision: [:review, :decline])
24
+ end
25
+
26
+ # Overriding method from core/models/order/queries.rb module
27
+ def need_reminding
28
+ super.where(kount_decision: nil)
29
+ end
30
+
31
+ # Find a current cart for a session. Returns a new order if one cannot be found.
32
+ #
33
+ # @param params [Hash]
34
+ # @return [Order]
35
+ #
36
+ def find_current(params = {})
37
+ if params[:id].present?
38
+ Order.not_placed.not_under_review.find(params[:id].to_s)
39
+ elsif params[:user_id].present?
40
+ Order.recently_updated.not_placed.not_under_review.find_by(params.slice(:user_id))
41
+ else
42
+ Order.new(user_id: params[:user_id])
43
+ end
44
+ rescue Mongoid::Errors::DocumentNotFound
45
+ Order.new(user_id: params[:user_id])
46
+ end
47
+ end
48
+
49
+ # Whether the FraudDecision#decision is `:review`.
50
+ def under_review?
51
+ !placed? && !canceled? && kount_decision == :review
52
+ end
53
+
54
+ def abandoned?
55
+ super && kount_decision.nil?
56
+ end
57
+
58
+ def set_kount_decision
59
+ self.kount_decision = fraud_decision.decision
60
+ end
61
+ end
62
+ end