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,9 @@
1
+ module Workarea
2
+ class Order
3
+ decorate FraudDecision do
4
+ def declined?
5
+ !decision.in?(%i[approved no_decision])
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Workarea
2
+ decorate Order::Item, with: :kount do
3
+ def unit_price_cents
4
+ return unless price_adjustments.present?
5
+ price_adjustments.first.unit.cents.to_f
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ module Workarea
2
+ class Order
3
+ module Status
4
+ class Review
5
+ include StatusCalculator::Status
6
+
7
+ def in_status?
8
+ order.under_review?
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Workarea
2
+ decorate Payment::SavedCreditCard, Payment::Tender::CreditCard, with: :kount do
3
+ decorated { field :kount_number, type: String }
4
+
5
+ def number=(val)
6
+ super
7
+ self.kount_number = Kount::SecurityMash.hash_credit_card(
8
+ number,
9
+ Workarea::Kount.ksalt
10
+ )
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Workarea
2
+ decorate Payment, with: :kount do
3
+ def needs_fraud_detection?
4
+ credit_card? || (Workarea::Plugin.installed?('Paypal') && paypal?)
5
+ end
6
+
7
+ def uses_credit_card?
8
+ credit_card? && credit_card.has_amount?
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Workarea
2
+ class Payment
3
+ module Status
4
+ class KountDeclined
5
+ include StatusCalculator::Status
6
+
7
+ def in_status?
8
+ Workarea::Order.find(@model.id).kount_decision == :decline
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Workarea
2
+ class Payment
3
+ module Status
4
+ class KountReview
5
+ include StatusCalculator::Status
6
+
7
+ def in_status?
8
+ Workarea::Order.find(@model.id).under_review?
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module Workarea
2
+ decorate Payment::Tender::CreditCard, with: :kount_tender do
3
+ private
4
+
5
+ def set_saved_card_values
6
+ super
7
+ self.kount_number = saved_card.kount_number if saved_card.present?
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module Workarea
2
+ decorate Search::Admin, with: :kount do
3
+ class_methods do
4
+ # The core code will try to use Workarea::Search::Admin::Order to index
5
+ # the Workarea::Kount::Order model, guard against it
6
+ def for(model)
7
+ return if model.class.to_s === "Workarea::Kount::Order"
8
+ super
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ decorate Search::Admin::Order, with: :kount do
3
+ def should_be_indexed?
4
+ model.placed? || model.kount_decision == :review || model.kount_decision == :declined
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,26 @@
1
+ module Workarea
2
+ decorate Shipping::RateLookup, with: :kount do
3
+ def response
4
+ ActiveShipping::RateResponse.new(
5
+ true, # success
6
+ 'success', # message
7
+ {}, # params
8
+ rates: valid_services.map do |service|
9
+ total = service.find_rate(subtotal).try(:price)
10
+ next unless total.present?
11
+
12
+ ActiveShipping::RateEstimate.new(
13
+ origin,
14
+ destination,
15
+ service.carrier,
16
+ service.name,
17
+ service_code: service.service_code,
18
+ total_price: total.cents,
19
+ currency: total.currency.to_s,
20
+ kount_code: service.kount_code
21
+ )
22
+ end.compact
23
+ )
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ module Workarea
2
+ decorate Shipping::Service, with: :kount do
3
+ decorated do
4
+ field :kount_code, type: String, default: 'ST'
5
+
6
+ validates :kount_code, inclusion: { in: %w(ST SD 2D ND) }
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Workarea
2
+ decorate Shipping::ServiceSelection, with: :kount do
3
+ decorated do
4
+ field :kount_code, type: String
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,27 @@
1
+ module Workarea
2
+ decorate ShippingOption, with: :kount do
3
+ decorated do
4
+ attr_reader :kount_code
5
+ end
6
+
7
+ class_methods do
8
+ def from_rate_estimate(rate)
9
+ new(
10
+ carrier: rate.carrier,
11
+ name: rate.service_name,
12
+ service_code: rate.service_code,
13
+ price: Money.new(rate.price, rate.currency),
14
+ tax_code: Shipping::Service.find_tax_code(
15
+ rate.carrier,
16
+ rate.service_name
17
+ ),
18
+ kount_code: rate.kount_code
19
+ )
20
+ end
21
+ end
22
+
23
+ def to_h
24
+ super.merge(kount_code: kount_code)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ module Workarea
2
+ module Kount
3
+ class CancelOrderUnderReview
4
+ attr_reader :order
5
+
6
+ def initialize(order)
7
+ @order = order
8
+ end
9
+
10
+ def cancel!
11
+ cancel_order_service.perform
12
+ cancel_order_side_effects
13
+ end
14
+
15
+ private
16
+
17
+ def cancel_order_service
18
+ @cancel_order_service ||= Workarea::CancelOrder.new(order, restock: true)
19
+ end
20
+
21
+ def cancel_order_side_effects
22
+ Workarea::Storefront::OrderMailer.hold_denial(order.id).deliver_now
23
+ order.update_attributes!(kount_decision: :decline)
24
+ Workarea::IndexAdminSearch.perform(order)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,43 @@
1
+ module Workarea
2
+ module Kount
3
+ class Event
4
+ def self.create(xml)
5
+ name = xml.xpath('name').text
6
+
7
+ case name
8
+ when /^DMC_/ then DmcEvent.new(name, xml)
9
+ when /^RISK_CHANGE_/ then RiskChangeEvent.new(name, xml)
10
+ when /^WORKFLOW_/ then WorkflowEvent.new(name, xml)
11
+ when /^SPECIAL_ALERT_/ then SpecialAlertEvent.new(name, xml)
12
+ end
13
+ end
14
+
15
+ attr_reader :name, :xml
16
+
17
+ def initialize(name, xml)
18
+ @name = name
19
+ @xml = xml
20
+ end
21
+
22
+ def key
23
+ @key ||= xml.xpath('key').text
24
+ end
25
+
26
+ def old_value
27
+ @old_value ||= xml.xpath('old_value').text
28
+ end
29
+
30
+ def new_value
31
+ @new_value ||= xml.xpath('new_value').text
32
+ end
33
+
34
+ def agent
35
+ @agent ||= xml.xpath('agent').text
36
+ end
37
+
38
+ def occurred
39
+ @occurred ||= xml.xpath('occurred').text
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,9 @@
1
+ module Workarea
2
+ module Kount
3
+ class DmcEvent < Event
4
+ def type
5
+ :dmc
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ module Workarea
2
+ module Kount
3
+ class RiskChangeEvent < Event
4
+ def type
5
+ :risk_change
6
+ end
7
+
8
+ def order_id
9
+ @order_id ||= xml.xpath('key').attribute('order_number').text
10
+ end
11
+
12
+ def site_id
13
+ @order_id ||= xml.xpath('key').attribute('site').text
14
+ end
15
+
16
+ def trasnaction_id
17
+ @trasnaction_id ||= xml.path('key').text
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module Workarea
2
+ module Kount
3
+ class SpecialAlertEvent < Event
4
+ def type
5
+ :special_alert
6
+ end
7
+
8
+ def order_id
9
+ @order_id ||= xml.xpath('key').attribute('order_number').text
10
+ end
11
+
12
+ def site_id
13
+ @order_id ||= xml.xpath('key').attribute('site').text
14
+ end
15
+
16
+ def trasnaction_id
17
+ @trasnaction_id ||= xml.path('key').text
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ module Workarea
2
+ module Kount
3
+ class WorkflowEvent < Event
4
+ def type
5
+ :workflow
6
+ end
7
+
8
+ def order_id
9
+ @order_id ||= xml.xpath('key').attribute('order_number').text
10
+ end
11
+
12
+ def site_id
13
+ @order_id ||= xml.xpath('key').attribute('site').text
14
+ end
15
+
16
+ def trasnaction_id
17
+ @trasnaction_id ||= xml.path('key').text
18
+ end
19
+
20
+ def approved?
21
+ new_value == "A"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ module Workarea
2
+ module Kount
3
+ class EventBatch
4
+ attr_reader :data, :xml
5
+
6
+ delegate :errors, to: :xml
7
+
8
+ def initialize(data)
9
+ @data = data
10
+ @xml = Nokogiri::XML.parse(@data)
11
+ end
12
+
13
+ def valid?
14
+ errors.empty?
15
+ end
16
+
17
+ def process!
18
+ events.each do |event|
19
+ next unless %w(RISK_CHANGE_REPLY WORKFLOW_STATUS_EDIT).include?(event.name)
20
+
21
+ event_string = event.xml.to_s.lines.map(&:strip).join
22
+ ProcessReviewOrder.perform_async(event.order_id, event.approved?, event_string)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def events
29
+ @events ||= begin
30
+ return [] if errors.present?
31
+
32
+ xml.xpath('events/event').map { |e| Workarea::Kount::Event.create(e) }
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,42 @@
1
+ module Workarea
2
+ module Kount
3
+ class OrderFraudUpdateService
4
+ delegate :gateway, to: Workarea::Kount
5
+
6
+ attr_reader :order, :payment, :mode, :options
7
+
8
+ def initialize(order:, payment:, mode: 'U', options: {})
9
+ @order = order
10
+ @payment = payment
11
+ @mode = mode
12
+ @options = options
13
+ end
14
+
15
+ def perform!
16
+ kount_order.update_attributes!(update_response: kount_response)
17
+ kount_response
18
+ end
19
+
20
+ def kount_order
21
+ @kount_order ||= Workarea::Kount::Order.find(order.id)
22
+ end
23
+
24
+ private
25
+
26
+ def update
27
+ Workarea::Kount::RisUpdate.new(
28
+ order: order,
29
+ payment: payment,
30
+ mode: mode,
31
+ options: options.merge(
32
+ kount_order: kount_order
33
+ )
34
+ ).to_h
35
+ end
36
+
37
+ def kount_response
38
+ @kount_response ||= gateway.call(update)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,120 @@
1
+ module Workarea
2
+ module Kount
3
+ class RisInquiry < RisRequest
4
+ attr_reader :shippings, :request_user_defined_fields
5
+
6
+ def initialize(order:, payment:, shippings:, mode: 'Q', request_user_defined_fields: {})
7
+ @order = order
8
+ @payment = payment
9
+ @shippings = shippings
10
+ @mode = mode
11
+ @request_user_defined_fields = request_user_defined_fields
12
+ end
13
+
14
+ def to_h
15
+ @to_h ||=
16
+ begin
17
+ inquiry_hash = [
18
+ base_fields,
19
+ shipping_address,
20
+ billing_address,
21
+ tender,
22
+ shipping_service,
23
+ order_total,
24
+ build_personal,
25
+ cart_fields
26
+ ].reduce(&:merge)
27
+
28
+ user_defined_fields.each do |key, value|
29
+ inquiry_hash.merge!("UDF[#{key}]" => value)
30
+ end
31
+
32
+ inquiry_hash
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def base_fields
39
+ super.merge(SITE: Kount.kount_site)
40
+ end
41
+
42
+ def order_total
43
+ {
44
+ TOTL: order.total_price.cents,
45
+ CURR: order.total_price.currency.iso_code
46
+ }
47
+ end
48
+
49
+ def build_personal
50
+ {
51
+ EMAL: order.email,
52
+ NAME: [payment.first_name, payment.last_name].join(' '),
53
+ IPAD: order.ip_address,
54
+ ORDR: order.id
55
+ }
56
+ end
57
+
58
+ def shipping_address
59
+ return {} unless order.requires_shipping?
60
+ Workarea::Kount::Address.for_shipping(shippings.first.address)
61
+ end
62
+
63
+ def billing_address
64
+ Workarea::Kount::Address.for_billing(payment.address)
65
+ end
66
+
67
+ def shipping_service
68
+ return {} unless order.requires_shipping? &&
69
+ shippings.first.shipping_service.try(:kount_code).try(:present?)
70
+
71
+ { SHTP: shippings.first.shipping_service.kount_code }
72
+ end
73
+
74
+ def cart_fields
75
+ cart = {
76
+ PROD_TYPE: [],
77
+ PROD_DESC: [],
78
+ PROD_ITEM: [],
79
+ PROD_PRICE: [],
80
+ PROD_QUANT: []
81
+ }
82
+ order.items.each do |order_item|
83
+ ris_product = RisInquiry::Product.new(order_item)
84
+ cart[:PROD_TYPE] << ris_product.type
85
+ cart[:PROD_DESC] << ris_product.description
86
+ cart[:PROD_ITEM] << ris_product.item
87
+ cart[:PROD_PRICE] << ris_product.price
88
+ cart[:PROD_QUANT] << ris_product.quantity
89
+ end
90
+
91
+ cart
92
+ end
93
+
94
+ def user_defined_fields
95
+ Workarea::Kount::UserDefinedFields.new(request_user_defined_fields).fields
96
+ end
97
+
98
+ def tender
99
+ if payment.credit_card? && payment.credit_card.number.present?
100
+ {
101
+ PTYP: Kount::PaymentTypes::CREDIT_CARD,
102
+ PTOK: Kount::SecurityMash.hash_credit_card(payment.credit_card.number, Kount.ksalt),
103
+ PENC: "KHASH"
104
+ }
105
+ elsif payment.credit_card? && payment.credit_card.token.present?
106
+ {
107
+ PTYP: Kount::PaymentTypes::TOKEN,
108
+ PTOK: Kount::SecurityMash.hash_credit_card(payment.credit_card.token, Kount.ksalt),
109
+ PENC: "KHASH"
110
+ }
111
+ elsif Workarea::Plugin.installed?('Paypal') && payment.paypal?
112
+ {
113
+ PTYP: Kount::PaymentTypes::PAYPAL,
114
+ PTOK: payment.paypal.payer_id
115
+ }
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end