workarea-kount 3.3.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 (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,8 @@
1
+ module Workarea
2
+ module Kount
3
+ class Engine < ::Rails::Engine
4
+ include Workarea::Plugin
5
+ isolate_namespace Workarea::Kount
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,2 @@
1
+ class Workarea::Kount::Errors < StandardError; end
2
+ class Workarea::Kount::Errors::PaymentNotSupportedError < Workarea::Kount::Errors; end
@@ -0,0 +1,50 @@
1
+ module Workarea
2
+ module Kount
3
+ class Gateway
4
+ delegate :merchant_id, :key, :ksalt, to: Workarea::Kount
5
+ attr_reader :options
6
+
7
+ RESPONSE_FORMAT = 'JSON'
8
+
9
+ VERSION = '0630'
10
+ ENDPOINT_PROD = 'https://risk.kount.net'
11
+ ENDPOINT_TEST = 'https://risk.test.kount.net'
12
+
13
+ def initialize(options = {})
14
+ @options = options
15
+ end
16
+
17
+ def call(body)
18
+ body = body.merge(VERS: VERSION, MERC: Kount.merchant_id, FRMT: RESPONSE_FORMAT)
19
+
20
+ response = RestClient::Resource
21
+ .new(endpoint, verify_ssl: verify_ssl_option, timeout: 1)
22
+ .post(body, x_kount_api_key: Kount.key)
23
+
24
+ begin
25
+ Response.new(JSON.parse(response))
26
+ rescue
27
+ Response.from_error(response.body)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def test?
34
+ options.fetch(:is_test, false)
35
+ end
36
+
37
+ def endpoint
38
+ test? ? ENDPOINT_TEST : ENDPOINT_PROD
39
+ end
40
+
41
+ def verify_ssl_option
42
+ if test?
43
+ OpenSSL::SSL::VERIFY_NONE
44
+ else
45
+ OpenSSL::SSL::VERIFY_PEER
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,195 @@
1
+ module Workarea
2
+ module Kount
3
+ class Mappings
4
+ MAPPING = {
5
+ # REQUEST INFO
6
+ version: 'VERS',
7
+ mode: 'MODE',
8
+ sdk: 'SDK',
9
+ merchant_id: 'MERC',
10
+ session_id: 'SESS',
11
+ merchant_order_number: 'ORDR',
12
+ site: 'SITE',
13
+ format: 'FRMT',
14
+ transaction_id: 'TRAN',
15
+
16
+ # MONEY
17
+ currency: 'CURR',
18
+ total: 'TOTL',
19
+ cash: 'CASH',
20
+
21
+ # USER INFO
22
+ phone_number: 'ANID',
23
+ email: 'EMAL',
24
+ customer_name: 'NAME',
25
+ dob: 'DOB',
26
+ gender: 'GENDER',
27
+
28
+ ship_to_name: 'S2NM',
29
+ ship_to_email: 'S2EM',
30
+
31
+ # SHIPPING ADDRESS
32
+ ship_to_address1: 'S2A1',
33
+ ship_to_address2: 'S2A2',
34
+ ship_to_city: 'S2CI',
35
+ ship_to_state: 'S2ST',
36
+ ship_to_postal: 'S2PC',
37
+ ship_to_country_code: 'S2CC',
38
+ ship_to_phone_number: 'S2PN',
39
+
40
+ # BILLING ADDRESS
41
+ bill_to_address1: 'B2A1',
42
+ bill_to_address2: 'B2A2',
43
+ bill_to_city: 'B2CI',
44
+ bill_to_state: 'B2ST',
45
+ bill_to_postal: 'B2PC',
46
+ bill_to_country_code: 'B2CC',
47
+ bill_to_phone_number: 'B2PN',
48
+
49
+ bill_to_premises: 'BPREMISE', # UK
50
+ bill_to_street: 'BSTREET', # UK
51
+ ship_to_premises: 'SPREMISE', # UK
52
+ ship_to_street: 'SSTREET', # UK
53
+
54
+ # PAYMENT
55
+ payment_type: 'PTYP',
56
+ payment_data: 'PTOK',
57
+ payment_encoding: 'PENC', # KASH
58
+
59
+ driver_license_number: 'DRIV',
60
+ customer_id: 'UNIQ',
61
+ customer_created_at: 'EPOC', # EPOC when user was created
62
+ ip_address: 'IPAD',
63
+ http_user_agent: 'UAGT',
64
+ shipping_type: 'SHPT',
65
+
66
+ # ORDER STATUS CODES
67
+ merchant_ack: 'MACK',
68
+ authorization_status: 'AUTH',
69
+ avs_zip_response: 'AVSZ',
70
+ avs_street_response: 'AVST',
71
+ cvv_response: 'CVVR',
72
+ refund_charge_back_status: 'RFCB'
73
+ }.freeze
74
+
75
+ AUTO_MAPPING = {
76
+ 'D' => :declined,
77
+ 'R' => :review,
78
+ 'E' => :manager_review,
79
+ 'A' => :approved
80
+ }.freeze
81
+
82
+ # Public: A hash that maps Kount response key names to readable Ruby symbols
83
+ RESPONSE_MAPPING = {
84
+ "VELO": :velocity,
85
+ "REGION": :region,
86
+ "FLASH": :flash,
87
+ "TRAN": :transaction_id,
88
+ "DEVICE_LAYERS": :device_layers,
89
+ "JAVASCRIPT": :javascript,
90
+ "HTTP_COUNTRY": :http_country,
91
+ "MODE": :mode,
92
+ "EMAILS": :emails,
93
+ "TIMEZONE": :timezone,
94
+ "MOBILE_TYPE": :mobile_type,
95
+ "WARNING_COUNT": :warning_count,
96
+ "REGN": :region,
97
+ "LOCALTIME": :localtime,
98
+ "COUNTRY": :country,
99
+ "REAS": :reason_variable,
100
+ "CARDS": :cards,
101
+ "PROXY": :proxy,
102
+ "VOICE_DEVICE": :voice_device,
103
+ "BRND": :payment_brand,
104
+ "NETW": :network,
105
+ "KAPT": :has_ris_record,
106
+ "FINGERPRINT": :fingerprint,
107
+ "COOKIES": :cookies,
108
+ "LANGUAGE": :language,
109
+ "RULES_TRIGGERED": :rules_triggered,
110
+ "SESS": :session_id,
111
+ "GEOX": :worst_contry_associated,
112
+ "DEVICES": :devices,
113
+ "VMAX": :vmax,
114
+ "SITE": :site,
115
+ "ORDR": :order_id,
116
+ "AUTO": :auto,
117
+ "SCOR": :score,
118
+ "COUNTERS_TRIGGERED": :counters_triggered,
119
+ "VERS": :version,
120
+ "MERC": :merchant_id,
121
+ "PC_REMOTE": :pc_remote,
122
+ "MOBILE_DEVICE": :mobile_device,
123
+ "MOBILE_FORWARDER": :mobile_forwarder,
124
+ "KYCF": :know_your_customer,
125
+ "ERROR_COUNT": :error_count,
126
+ "ERRO": :error
127
+ }.freeze
128
+
129
+ # Public: A hash that maps Kount Error Numbers to Error Codes
130
+ ERRORS = {
131
+ '201': 'MISSING_VERS',
132
+ '202': 'MISSING_MODE',
133
+ '203': 'MISSING_MERC',
134
+ '204': 'MISSING_SESS',
135
+ '205': 'MISSING_TRAN',
136
+ '211': 'MISSING_CURR',
137
+ '212': 'MISSING_TOTL',
138
+ '221': 'MISSING_EMAL',
139
+ '222': 'MISSING_ANID',
140
+ '223': 'MISSING_SITE',
141
+ '231': 'MISSING_PTYP',
142
+ '232': 'MISSING_CARD',
143
+ '233': 'MISSING_MICR',
144
+ '234': 'MISSING_PYPL',
145
+ '235': 'MISSING_PTOK',
146
+ '241': 'MISSING_IPAD',
147
+ '251': 'MISSING_MACK',
148
+ '261': 'MISSING_POST',
149
+ '271': 'MISSING_PROD_TYPE',
150
+ '272': 'MISSING_PROD_ITEM',
151
+ '273': 'MISSING_PROD_DESC',
152
+ '274': 'MISSING_PROD_QUANT',
153
+ '275': 'MISSING_PROD_PRICE',
154
+ '301': 'BAD_VERS',
155
+ '302': 'BAD_MODE',
156
+ '303': 'BAD_MERC',
157
+ '304': 'BAD_SESS',
158
+ '305': 'BAD_TRAN',
159
+ '311': 'BAD_CURR',
160
+ '312': 'BAD_TOTL',
161
+ '321': 'BAD_EMAL',
162
+ '322': 'BAD_ANID',
163
+ '323': 'BAD_SITE',
164
+ '324': 'BAD_FRMT',
165
+ '331': 'BAD_PTYP',
166
+ '332': 'BAD_CARD',
167
+ '333': 'BAD_MICR',
168
+ '334': 'BAD_PYPL',
169
+ '335': 'BAD_GOOG',
170
+ '336': 'BAD_BLML',
171
+ '337': 'BAD_PENC',
172
+ '341': 'BAD_IPAD',
173
+ '351': 'BAD_MACK',
174
+ '362': 'BAD_CART',
175
+ '371': 'BAD_PROD_TYPE',
176
+ '372': 'BAD_PROD_ITEM',
177
+ '373': 'BAD_PROD_DESC',
178
+ '374': 'BAD_PROD_QUANT',
179
+ '375': 'BAD_PROD_PRICE',
180
+ '399': 'BAD_OPTN',
181
+ '401': 'EXTRA_DATA',
182
+ '402': 'MISMATCH_PTYP',
183
+ '403': 'UNNECESSARY_ANID',
184
+ '404': 'UNNECESSARY_PTOK',
185
+ '501': 'UNAUTH_REQ',
186
+ '502': 'UNAUTH_MERC',
187
+ '503': 'UNAUTH_IP',
188
+ '504': 'UNAUTH_PASS',
189
+ '601': 'SYS_ERR',
190
+ '602': 'SYS_NOPROCESS',
191
+ '701': 'NO_HDR'
192
+ }.freeze
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,50 @@
1
+ module Workarea
2
+ module Kount
3
+ class PaymentTypes
4
+ # Credit card (VISA, MasterCard, Amercian Express, etc)
5
+ CREDIT_CARD = 'CARD'
6
+ #Generic Token
7
+ TOKEN = 'TOKEN'
8
+ # PayPal
9
+ PAYPAL = 'PYPL'
10
+ # Check
11
+ CHECK = 'CHEK'
12
+ # Merchant issued gift card (not the ones with VISA/MC on them)
13
+ GIFT_CARD = 'GIFT'
14
+ # Carte Bleue
15
+ CARTE_BLEUE = 'CARTE_BLEUE'
16
+ # Sofort
17
+ SOFORT = 'SOFORT'
18
+ # Elv
19
+ ELV = 'ELV'
20
+ # Poli
21
+ POLI = 'POLI'
22
+ # Neteller
23
+ NETELLER = 'NETELLER'
24
+ # Giropay
25
+ GIROPAY = 'GIROPAY'
26
+ # BPay
27
+ BPAY = 'BPAY'
28
+ # Interac
29
+ INTERAC = 'INTERAC'
30
+ # Apple Pay
31
+ APPLE_PAY = 'APAY'
32
+ # Skrill
33
+ SKRILL = 'SKRILL'
34
+ # Moneybooker (basically another name for Skrill)
35
+ MONEYBOOKERS = 'SKRILL'
36
+ # Mercado Pago
37
+ MERCADO_PAGO = 'MERCADE_PAGO'
38
+ # Bill Me Later
39
+ BILL_ME_LATER = 'BLML'
40
+ # Google Checkout
41
+ GOOGLE_CHECKOUT = 'GOOG'
42
+ # Green Dot Money Pack
43
+ GREEN_DOT_MONEY_PACK = 'GDMP'
44
+ # Single Euro Payments Area
45
+ SINGLE_EURO_PAYMENTS_AREA = 'SEPA'
46
+ # None
47
+ NONE = 'NONE'
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,141 @@
1
+ module Workarea
2
+ module Kount
3
+ class Response
4
+ attr_reader :body
5
+ delegate :keys, :[], to: :body
6
+
7
+ def self.from_error(error_string)
8
+ body = error_string.strip.split("\n").each_with_object({}) do |string, response|
9
+ key, value = string.split("=")
10
+ response[key] = value
11
+ end
12
+
13
+ Response.new(body)
14
+ end
15
+
16
+ def initialize(body)
17
+ @body = body
18
+ end
19
+
20
+ def result_hash
21
+ @result_hash ||=
22
+ begin
23
+ body_dup = body.dup
24
+ rule_ids = []
25
+ rule_descriptions = []
26
+
27
+ errors = []
28
+ warnings = []
29
+
30
+ body_dup.each do |key, value|
31
+ if key =~ /^RULE_ID_(\d+)/
32
+ rule_ids[$1.to_i] = value
33
+ body_dup.delete(key)
34
+ end
35
+
36
+ if key =~ /^RULE_DESCRIPTION_(\d+)/
37
+ rule_descriptions[$1.to_i] = value
38
+ body_dup.delete(key)
39
+ end
40
+
41
+ if key =~ /^WARNING_(\d+)/
42
+ warnings[$1.to_i] = value
43
+ body_dup.delete(key)
44
+ end
45
+
46
+ if key =~ /^ERROR_(\d+)/
47
+ errors[$1.to_i] = value
48
+ body_dup.delete(key)
49
+ end
50
+ end
51
+
52
+ if rule_ids.present?
53
+ rules = rule_ids.each_with_index.map do |rule_id, i|
54
+ { rule_id: rule_id, rule_description: rule_descriptions[i] }
55
+ end
56
+ end
57
+
58
+ response_values = body_dup.map do |key, value|
59
+ [
60
+ Workarea::Kount::Mappings::RESPONSE_MAPPING.fetch(key, key),
61
+ value
62
+ ]
63
+ end.to_h
64
+
65
+ response_values.merge(
66
+ rules: rules,
67
+ errors_kount: errors, # this was named this way, b/c of how ActiveRecord handles "errors=", ugh!
68
+ warnings: warnings
69
+ )
70
+ end
71
+ end
72
+
73
+ def triggered_rules
74
+ result_hash[:rules]
75
+ end
76
+
77
+ # Symbol for the decision made by Kount
78
+ #
79
+ # Returns a symbol for the decision made by Kount
80
+ def decision
81
+ Workarea::Kount::Mappings::AUTO_MAPPING.fetch(result_hash["AUTO"], :approve)
82
+ end
83
+
84
+ def transaction_id
85
+ body["TRAN"]
86
+ end
87
+
88
+ def success?
89
+ body["MODE"] != "E" && result_hash["ERROR_COUNT"].to_i == 0
90
+ end
91
+
92
+ def score
93
+ body["SCOR"]
94
+ end
95
+
96
+ def credit_cards
97
+ body["CARDS"]
98
+ end
99
+
100
+ def email_addresses
101
+ body["EMAILS"]
102
+ end
103
+
104
+ def devices
105
+ body["DEVICES"]
106
+ end
107
+
108
+ def mongoize
109
+ body
110
+ end
111
+
112
+ class << self
113
+ def demongoize(object)
114
+ return nil if object.blank?
115
+
116
+ Response.new(object)
117
+ end
118
+
119
+ def mongoize(object)
120
+ case object
121
+ when Response then object.mongoize
122
+ else object
123
+ end
124
+ end
125
+
126
+ def evolve(object)
127
+ raise 'querying on an Workarea::Kount::Response is unsupported at this time'
128
+ end
129
+ end
130
+
131
+ private
132
+
133
+ # Takes the raw_response and parses it to key values for the
134
+ # keyvalue format
135
+ #
136
+ # Returns a hash of key values
137
+ def parsed_response
138
+ end
139
+ end
140
+ end
141
+ end